1. Introduction and Aims

We have merged the two datasets together in GCSKO_merge.Rmd. We also subsetted out the pre-sexual-branch and the sexual cells (male and female) and stored them in a Seurat object called tenx.mutant.integrated.sex. Here, we will perform pseudotime analysis on the dataset and build modules of genes that show similar expression across this pseudotime.

2. Read in the data

Load/Install the Required Packages

[1] "patchwork is loaded correctly"
[1] "viridis is loaded correctly"
[1] "Seurat is loaded correctly"
[1] "cowplot is loaded correctly"
[1] "gridExtra is loaded correctly"
[1] "grid is loaded correctly"
[1] "Hmisc is loaded correctly"
[1] "reshape2 is loaded correctly"
[1] "dplyr is loaded correctly"
[1] "monocle3 is loaded correctly"
Loading required package: destiny
there is no package called ‘destiny’
[1] "trying to install destiny"
Bioconductor version 3.11 (BiocManager 1.30.10), R 4.0.2 (2020-06-22)
Installing package(s) 'destiny'
also installing the dependencies ‘DEoptimR’, ‘xts’, ‘robustbase’, ‘vcd’, ‘laeken’, ‘ranger’, ‘TTR’, ‘pcaMethods’, ‘ggplot.multistats’, ‘ggthemes’, ‘VIM’, ‘knn.covertree’, ‘smoother’, ‘scatterplot3d’

cannot open URL 'https://bioconductor.org/packages/3.11/data/annotation/bin/macosx/contrib/4.0/PACKAGES.rds': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/data/annotation/bin/macosx/contrib/4.0/PACKAGES.gz': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/data/experiment/bin/macosx/contrib/4.0/PACKAGES.rds': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/data/experiment/bin/macosx/contrib/4.0/PACKAGES.gz': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/workflows/bin/macosx/contrib/4.0/PACKAGES.rds': HTTP status was '404 Not Found'cannot open URL 'https://bioconductor.org/packages/3.11/workflows/bin/macosx/contrib/4.0/PACKAGES.gz': HTTP status was '404 Not Found'Package which is only available in source form, and may need
  compilation of C/C++/Fortran: ‘destiny’
trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/DEoptimR_1.0-8.tgz'
Content type 'application/x-gzip' length 39620 bytes (38 KB)
==================================================
downloaded 38 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/xts_0.12.1.tgz'
Content type 'application/x-gzip' length 927873 bytes (906 KB)
==================================================
downloaded 906 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/robustbase_0.93-6.tgz'
Content type 'application/x-gzip' length 3300888 bytes (3.1 MB)
==================================================
downloaded 3.1 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/vcd_1.4-7.tgz'
Content type 'application/x-gzip' length 1557206 bytes (1.5 MB)
==================================================
downloaded 1.5 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/laeken_0.5.1.tgz'
Content type 'application/x-gzip' length 2913969 bytes (2.8 MB)
==================================================
downloaded 2.8 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ranger_0.12.1.tgz'
Content type 'application/x-gzip' length 2003695 bytes (1.9 MB)
==================================================
downloaded 1.9 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/TTR_0.24.2.tgz'
Content type 'application/x-gzip' length 525804 bytes (513 KB)
==================================================
downloaded 513 KB

trying URL 'https://bioconductor.org/packages/3.11/bioc/bin/macosx/contrib/4.0/pcaMethods_1.80.0.tgz'
Content type 'application/x-gzip' length 1197476 bytes (1.1 MB)
==================================================
downloaded 1.1 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ggplot.multistats_1.0.0.tgz'
Content type 'application/x-gzip' length 29775 bytes (29 KB)
==================================================
downloaded 29 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/ggthemes_4.2.0.tgz'
Content type 'application/x-gzip' length 426524 bytes (416 KB)
==================================================
downloaded 416 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/VIM_6.0.0.tgz'
Content type 'application/x-gzip' length 1738658 bytes (1.7 MB)
==================================================
downloaded 1.7 MB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/knn.covertree_1.0.tgz'
Content type 'application/x-gzip' length 686790 bytes (670 KB)
==================================================
downloaded 670 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/smoother_1.1.tgz'
Content type 'application/x-gzip' length 22584 bytes (22 KB)
==================================================
downloaded 22 KB

trying URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/scatterplot3d_0.3-41.tgz'
Content type 'application/x-gzip' length 333688 bytes (325 KB)
==================================================
downloaded 325 KB

The downloaded binary packages are in
    /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/downloaded_packages
installing the source package ‘destiny’

trying URL 'https://bioconductor.org/packages/3.11/bioc/src/contrib/destiny_3.2.0.tar.gz'
Content type 'application/x-gzip' length 8979926 bytes (8.6 MB)
==================================================
downloaded 8.6 MB

* installing *source* package ‘destiny’ ...
** using staged installation
** libs
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/grDevices/include' -I/usr/local/include  -ggdb -fPIC  -Wall -g -O2  -c RcppExports.cpp -o RcppExports.o
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:1:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Core:535:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:2:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/LU:47:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:12:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Jacobi:29:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/QR:17:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Householder:27:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:5:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SVD:48:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:6:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Geometry:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Eigenvalues:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:26:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCore:66:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:27:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/OrderingMethods:71:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:29:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseQR:35:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:33:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/IterativeLinearSolvers:46:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/CholmodSupport:45:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:35:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/KroneckerProduct:34:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:39:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/Polynomials:135:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from RcppExports.cpp:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:40:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/SparseExtra:51:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
17 warnings generated.
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/grDevices/include' -I/usr/local/include  -ggdb -fPIC  -Wall -g -O2  -c censoring.cpp -o censoring.o
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:1:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Core:535:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:2:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/LU:47:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:12:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Jacobi:29:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:3:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Cholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:4:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/QR:17:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Householder:27:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:5:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SVD:48:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:6:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Geometry:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:30:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Dense:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Eigenvalues:58:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:26:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCore:66:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:27:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/OrderingMethods:71:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:29:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseCholesky:43:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/SparseQR:35:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:31:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/Sparse:33:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/IterativeLinearSolvers:46:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:32:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/CholmodSupport:45:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:35:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/KroneckerProduct:34:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:39:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/Polynomials:135:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
In file included from censoring.cpp:7:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigen.h:25:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/RcppEigenForward.h:40:
In file included from /Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/SparseExtra:51:
/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include/unsupported/Eigen/../../Eigen/src/Core/util/ReenableStupidWarnings.h:10:30: warning: pragma diagnostic pop could not pop, no matching push [-Wunknown-pragmas]
    #pragma clang diagnostic pop
                             ^
censoring.cpp:60:15: warning: variable 'm0' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:71:20: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                               ^~
censoring.cpp:60:11: note: remove the 'if' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:60:15: warning: variable 'm0' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~
censoring.cpp:71:20: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                               ^~
censoring.cpp:60:15: note: remove the '&&' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~
censoring.cpp:55:13: note: initialize the variable 'm0' to silence this warning
                        double m0, m1;
                                 ^
                                  = 0.0
censoring.cpp:60:15: warning: variable 'm1' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:71:48: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                                                           ^~
censoring.cpp:60:11: note: remove the 'if' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:60:15: warning: variable 'm1' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~
censoring.cpp:71:48: note: uninitialized use occurs here
                                * ( std::erfc((m0-v) / sigma) - std::erfc((m1-v) / sigma) )
                                                                           ^~
censoring.cpp:60:15: note: remove the '&&' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~
censoring.cpp:55:17: note: initialize the variable 'm1' to silence this warning
                        double m0, m1;
                                     ^
                                      = 0.0
censoring.cpp:60:15: warning: variable 'use_d' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:66:21: note: uninitialized use occurs here
                        const double v = use_d ? d : c;
                                         ^~~~~
censoring.cpp:60:11: note: remove the 'if' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
censoring.cpp:60:15: warning: variable 'use_d' is used uninitialized whenever '&&' condition is false [-Wsometimes-uninitialized]
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~
censoring.cpp:66:21: note: uninitialized use occurs here
                        const double v = use_d ? d : c;
                                         ^~~~~
censoring.cpp:60:15: note: remove the '&&' if its condition is always true
                        } else if (!one_uncertain && one_missing) {
                                   ^~~~~~~~~~~~~~~~~
censoring.cpp:18:12: note: initialize the variable 'use_d' to silence this warning
        bool use_d;
                  ^
                   = false
23 warnings generated.
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG  -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/Rcpp/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/RcppEigen/include' -I'/Library/Frameworks/R.framework/Versions/4.0/Resources/library/grDevices/include' -I/usr/local/include  -ggdb -fPIC  -Wall -g -O2  -c utils.cpp -o utils.o
clang++ -mmacosx-version-min=10.13 -std=gnu++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/lib -o destiny.so RcppExports.o censoring.o utils.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
installing to /Library/Frameworks/R.framework/Versions/4.0/Resources/library/00LOCK-destiny/00new/destiny/libs
** R
** data
** demo
** inst
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** installing vignettes
** testing if installed package can be loaded from temporary location
** checking absolute paths in shared objects and dynamic libraries
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (destiny)

The downloaded source packages are in
    ‘/private/var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T/RtmpXGhNV1/downloaded_packages’
Old packages: 'ape', 'backports', 'callr', 'car', 'ComplexHeatmap',
  'conquer', 'cowplot', 'data.table', 'deldir', 'devtools', 'dplyr',
  'DT', 'fields', 'fs', 'glue', 'Hmisc', 'jsonlite', 'lmtest',
  'maptools', 'MASS', 'mgcv', 'nlme', 'pbapply', 'processx', 'ps',
  'quantreg', 'RcppArmadillo', 'RcppHNSW', 'remotes', 'renv', 'Seurat',
  'sf', 'shape', 'stringi', 'sys', 'tidyr', 'vctrs', 'xfun', 'zip'
Update all/some/none? [a/s/n]: 
Loading required package: destiny

Attaching package: ‘destiny’

The following object is masked from ‘package:SummarizedExperiment’:

    distance

The following object is masked from ‘package:GenomicRanges’:

    distance

The following object is masked from ‘package:IRanges’:

    distance
[1] "destiny installed and loaded"

load data

## load sex only branch cells saved from GCSKO_Sex_Branch_Analysis.Rmd
## Restore the objects
## load sex branch dataset
tenx.mutant.integrated.sex <- readRDS("../data_to_export/tenx.mutant.integrated.sex.RDS")
## load full dataset
#tenx.mutant.integrated <- readRDS("../data_to_export/tenx.mutant.integrated.RDS")
## add old pt values
## these values are calculated in hte GCSKO_pseudotime_allcells.Rmd script and so were added after the object was split into sex only.
tenx.all <- readRDS("../data_to_export/tenx.mutant.integrated.RDS")
tenx.all.meta <- as.data.frame(tenx.all@meta.data)
tenx.all.meta <- tenx.all.meta[which(rownames(tenx.all.meta) %in% rownames(tenx.mutant.integrated.sex@meta.data)),]
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, tenx.all.meta$old_pt_values, col.name = "old_pt_values")
## then remove these objects so they don't use up memory
rm(c(tenx.all, tenx.all.meta))
Error in rm(c(tenx.all, tenx.all.meta)) : 
  ... must contain names or character strings

3. Dimensionalty Reduction

We will now re-calculate the UMAP, PCA and diffusion map to visualise the data since the old visualisation used the variation in the whole dataset and so some of the variation in this set of cells was obscured.

ref: https://github.com/satijalab/seurat/issues/1883

A. Recalculate PCA

The PCA is used as the basis of other dimensionality reductions so we will now recalculate this to get to our final UMAP.

First, run PCA again

tenx.mutant.integrated.sex <- RunPCA(tenx.mutant.integrated.sex, npcs = 30, verbose = FALSE)

Then inspect the PCs

ElbowPlot(tenx.mutant.integrated.sex, ndims = 30, reduction = "pca")

Have a quick look at the output

FeaturePlot(tenx.mutant.integrated.sex, reduction = "pca", pt.size = 0.01, features = "old_pt_values")

B. UMAP

calculate UMAP

## run UMAP
tenx.mutant.integrated.sex <- RunUMAP(tenx.mutant.integrated.sex, reduction = "pca", dims = 1:15, n.neighbors = 20, seed.use = 1234, min.dist = 0.5, repulsion.strength = 0.05, reduction.name = "umapoptimised_post_repca")
23:35:10 UMAP embedding parameters a = 0.583 b = 1.334
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
23:35:10 Read 3691 rows and found 15 numeric columns
23:35:10 Using Annoy for neighbor search, n_neighbors = 20
Found more than one class "dist" in cache; using the first, from namespace 'spam'
Also defined by ‘BiocGenerics’
23:35:10 Building Annoy index with metric = cosine, n_trees = 50
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
23:35:12 Writing NN index file to temp file /var/folders/wj/rztzclxn1t10cl2sk0plbf3r0000gn/T//RtmpXGhNV1/file433730789f55
23:35:12 Searching Annoy index using 1 thread, search_k = 2000
23:35:13 Annoy recall = 100%
23:35:17 Commencing smooth kNN distance calibration using 1 thread
23:35:19 Initializing from normalized Laplacian + noise
23:35:19 Commencing optimization for 500 epochs, with 104270 positive edges
0%   10   20   30   40   50   60   70   80   90   100%
[----|----|----|----|----|----|----|----|----|----|
**************************************************|
23:35:25 Optimization finished
Cannot add objects with duplicate keys (offending key: UMAP_), setting key to 'umapoptimised_post_repca_'
## plot
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, split.by = "genotype_combined") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

check markers to orientate

plots <- FeaturePlot(tenx.mutant.integrated.sex, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE, reduction = "umapoptimised_post_repca")

plots[[3]] + NoLegend()  # Get just the co-expression plot, built-in legend is meaningless for this plot

plots[[4]] # Get just the key

CombinePlots(plots[3:4], legend = 'none', ncol =2, nrow = 1, rel_widths = c(2, 1), rel_heights = c(4,1)) # Stitch the co-expression and key plots together
CombinePlots is being deprecated. Plots should now be combined using the patchwork system.

4. Clustering

Generate New Clusters

We must now recalculate the clusters to gain a better understanding of the heterogeneity of the subset. Since using the previous clusters, the asexual cells obscured some of the variation.

## copy old clusters
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, tenx.mutant.integrated.sex@meta.data$seurat_clusters, col.name = "pre_sex_clusters")
## generate new clusters at various resolutions
tenx.mutant.integrated.sex <- FindNeighbors(tenx.mutant.integrated.sex, dims = 1:15)
tenx.mutant.integrated.sex <- FindClusters(tenx.mutant.integrated.sex, resolution = c(2,3,4,5,6), random.seed = 42, algorithm = 2)

Visualise

Choose Cluster Resolution

View the clusters at different resolutions to chose the appropraite resolution

## plot
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.2") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.3") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.4") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.5") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.6") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Go with 4 clusters

tenx.mutant.integrated.sex <- FindClusters(tenx.mutant.integrated.sex, resolution = 4, random.seed = 42, algorithm = 2)

DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5) +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Original UMAP

You can also use the original UMAP projection

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5) +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Representation

look at cluster representation

plot

## this function writes the next bit of code for you
ploty <- c()
for(i in seq_along(levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters))){
  ploty <- paste0(ploty, "list_UMAPs_by_cluster[[", i, "]]", " + ")
}
## plot
library(gridExtra)
grid.arrange(list_UMAPs_by_cluster[[1]] , list_UMAPs_by_cluster[[2]] , list_UMAPs_by_cluster[[3]] , list_UMAPs_by_cluster[[4]] , list_UMAPs_by_cluster[[5]] , list_UMAPs_by_cluster[[6]] , list_UMAPs_by_cluster[[7]] , list_UMAPs_by_cluster[[8]] , list_UMAPs_by_cluster[[9]] , list_UMAPs_by_cluster[[10]] , list_UMAPs_by_cluster[[11]] , list_UMAPs_by_cluster[[12]] , list_UMAPs_by_cluster[[13]] , list_UMAPs_by_cluster[[14]] , list_UMAPs_by_cluster[[15]] , list_UMAPs_by_cluster[[16]] , list_UMAPs_by_cluster[[17]] , list_UMAPs_by_cluster[[18]] , list_UMAPs_by_cluster[[19]] , list_UMAPs_by_cluster[[20]] , list_UMAPs_by_cluster[[21]] , list_UMAPs_by_cluster[[22]] , list_UMAPs_by_cluster[[23]] , list_UMAPs_by_cluster[[24]] , list_UMAPs_by_cluster[[25]] , list_UMAPs_by_cluster[[26]] , list_UMAPs_by_cluster[[27]] , list_UMAPs_by_cluster[[28]] , list_UMAPs_by_cluster[[29]] , list_UMAPs_by_cluster[[30]] , list_UMAPs_by_cluster[[31]], ncol = 5)
## for loop which takes each cluster and makes a list of cells and then plots a highlighted plot and adds it to a list

## make a df of the number of 
n_per_cluster <- as.data.frame(table(tenx.mutant.integrated.sex@meta.data$seurat_clusters))
rownames(n_per_cluster) <- n_per_cluster$Var1
n_per_cluster <- n_per_cluster[,2]

## make a blank list
list_UMAPs_by_cluster <- vector(mode = "list", length = length(levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters)))

## for loop
for(i in seq_along(levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters))){
  ## make a list of cells
  list_of_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters == levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters)[i]), ])
  umap_plot <- DimPlot(tenx.mutant.integrated.sex,  reduction = "umap", label = FALSE, repel = TRUE, pt.size = 0.1, cells.highlight = list_of_cells) + 
  coord_fixed() + 
  scale_color_manual(values=c("#000000", "#f54e1e")) + 
  theme_void() + 
  labs(title = paste("cluster", levels(tenx.mutant.integrated.sex@meta.data$seurat_clusters)[i], "\n", "(n = ", n_per_cluster[i],")")) + 
  theme(plot.title = element_text(hjust = 0.5), legend.position = "none")
  ## add to the list
  list_UMAPs_by_cluster[[i]] <- umap_plot
}
## plot
grid.arrange(list_UMAPs_by_cluster[[1]] , list_UMAPs_by_cluster[[2]] , list_UMAPs_by_cluster[[3]] , list_UMAPs_by_cluster[[4]] , list_UMAPs_by_cluster[[5]] , list_UMAPs_by_cluster[[6]] , list_UMAPs_by_cluster[[7]] , list_UMAPs_by_cluster[[8]] , list_UMAPs_by_cluster[[9]] , list_UMAPs_by_cluster[[10]] , list_UMAPs_by_cluster[[11]] , list_UMAPs_by_cluster[[12]] , list_UMAPs_by_cluster[[13]] , list_UMAPs_by_cluster[[14]] , list_UMAPs_by_cluster[[15]] , list_UMAPs_by_cluster[[16]] , list_UMAPs_by_cluster[[17]] , list_UMAPs_by_cluster[[18]] , list_UMAPs_by_cluster[[19]] , list_UMAPs_by_cluster[[20]] , list_UMAPs_by_cluster[[21]] , list_UMAPs_by_cluster[[22]] , list_UMAPs_by_cluster[[23]] , list_UMAPs_by_cluster[[24]] , list_UMAPs_by_cluster[[25]] , list_UMAPs_by_cluster[[26]] , list_UMAPs_by_cluster[[27]] , list_UMAPs_by_cluster[[28]] , list_UMAPs_by_cluster[[29]] , list_UMAPs_by_cluster[[30]] , list_UMAPs_by_cluster[[31]], ncol = 5)

Show correspondance with old clusters (Alluvium plot, Sankey diagram)

##This is the set up for this:
## two clusters that differ
table(tenx.mutant.integrated.sex@meta.data$seurat_clusters, tenx.mutant.integrated.sex@meta.data$pre_sex_clusters)
## make a dataframe that is the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated.sex@meta.data)

df_alluvial <- melt(table(data.frame(full_clusters = df_meta_data$pre_sex_clusters, sex_clusters = df_meta_data$seurat_clusters)))

## load required package
library(ggalluvial)

## plot
ggplot(df_alluvial, aes(y = value, axis1 = full_clusters, axis2 = sex_clusters)) +
  geom_alluvium(aes(fill = sex_clusters),
                width = 0, knot.pos = 0, reverse = FALSE) +
  guides(fill = FALSE) +
  geom_stratum(width = 1/8, reverse = FALSE) +
  geom_text(stat = "stratum", infer.label = TRUE, reverse = FALSE) +
  scale_x_continuous(breaks = 1:2, labels = c("original cluster", "Sex Cluster")) +
  coord_flip() +
  ggtitle("Cluster Identiity in full dataset vs. sex only") +
    theme_classic()

Show representation of genotypes per cluster

prep for dotplot

## make a dataframe that is the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated.sex@meta.data)

## define order for plotting 
my_levels_sex <- c("0", "9", "28", "2", "29", "16", "22", "23", "15", "21", "30", "4", "3", "18", "7", "8", "6", "20", "12", "26", "13", "5", "11", "25", "1", "17", "10", "24", "14", "27", "19")

## redefine order of clusters:
df_meta_data$seurat_clusters <- factor(x = df_meta_data$seurat_clusters, levels = my_levels_sex)

## make a new df of CLUSTER and IDENTITY
dot_plot_df <- as.data.frame.matrix(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined))
dot_plot_df$cluster <- rownames(dot_plot_df)

## calculate percentage of cells for each genotype
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined), margin = 2)) * 100)

## make a column for cluster names
dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)

## melt dataframe for plotting
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"

## melt the raw number too
dot_plot_df_melted <- melt(dot_plot_df, variable.name = "cluster")
colnames(dot_plot_df_melted)[2] <- "identity"
colnames(dot_plot_df_melted)[3] <- "raw_number"

## merge together
identical(dot_plot_df_melted$cluster, dot_plot_df_pc_melted$cluster)
dot_plot_merged <- cbind(dot_plot_df_melted, dot_plot_df_pc_melted)
dot_plot_merged <- dot_plot_merged[,c(1,2,3,6)]

## redefine order of clusters
dot_plot_merged$cluster <- factor(x = dot_plot_merged$cluster, levels = my_levels_sex)

## where values are zero, add NA
## find wells where it's zero
zero_values <- dot_plot_merged$value == 0
dot_plot_merged$value[zero_values] <- NA

## also do for raw number
zero_values <- dot_plot_merged$raw_number == 0
dot_plot_merged$raw_number[zero_values] <- NA

## reorder x axis:
my_levels_genotype <- c("GCSKO-oom", "GCSKO-29", "GCSKO-2", "GCSKO-19", "GCSKO-3", "GCSKO-21", "GCSKO-13", "GCSKO-28", "GCSKO-10_820", "GCSKO-17", "GCSKO-20", "WT", "WT_10X")

dot_plot_merged$identity <- factor(x = dot_plot_merged$identity, levels = my_levels_genotype)

plot

## plot
dot_plot_identity <- ggplot(dot_plot_merged, aes(y = factor(cluster), x = factor(identity))) +
      ## make into a dot plot
      geom_point(aes(colour=value, size=raw_number)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 0, max(dot_plot_df_pc_melted$value)), na.value="white") +
      #change the colours
      scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white") +
      theme_classic() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), text=element_text(size=16,  family="Arial")) +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, angle=45, hjust=1, vjust=1), axis.text.y=element_text(size=12,), legend.position = "bottom", plot.margin = unit(c(1,3,1,3), "lines")) +
    ## annotate males
    geom_hline(aes(yintercept = 5.5)) +
    ## annotate females
    geom_hline(aes(yintercept = 20.5)) +
    ## annotate pheno 1
    geom_vline(aes(xintercept = 4.5)) +
    ## annotate pheno 2
    geom_vline(aes(xintercept = 5.5)) +    
    ## annotate pheno 3
    geom_vline(aes(xintercept = 7.5)) +
    ## annotate pheno 4
    geom_vline(aes(xintercept = 11.5))

## print
print(dot_plot_identity)

4. Slingshot and SCMAP

We can then use Slingshot to plot a Pseudotime and extract mutually exclusive parts of the trajectory (Male and Female) as well as the common stalk of both trajectories.

Slingshot

packages

library(slingshot)
library(scater)

Data In

## extract the data from the objects and save to export to Arthur
integrated_sex_counts <- tenx.mutant.integrated.sex@assays$integrated@data
integrated_sex_pheno <- tenx.mutant.integrated.sex@meta.data
#saveRDS(integrated_sex_counts, file="~/data_to_export/integrated_sex_counts.RDS")
#saveRDS(integrated_sex_pheno, file="~/data_to_export/integrated_sex_pheno.RDS")
#sexcount<-readRDS("/Users/talman/Google\ Drive/ActiveSanger/sexpaper/integrated_sex_counts.RDS")
#sexpheno<-readRDS("/Users/talman/Google\ Drive/ActiveSanger/sexpaper/integrated_sex_pheno.RDS")
sexcount <- integrated_sex_counts
sexpheno <- integrated_sex_pheno

## technically this is a shortcut but it didn't work
##https://satijalab.org/seurat/v3.1/conversion_vignette.html
#convert Seurat to SCE object:
#pbmc.sce <- as.SingleCellExperiment(tenx.mutant.integrated.sex), assay = "integrated")

slingshot on PCA

Preprocess

## make a single cell experiment object, which is the input for Slingshot
sexbranch <- SingleCellExperiment(assays = list(
  counts = as.matrix(sexcount),
  logcounts = as.matrix(sexcount)
), colData = sexpheno)

## subset wild-type cells
sexbranchWT<- sexbranch[, colData(sexbranch)$genotype == "WT"|colData(sexbranch)$experiment == "tenx_5k"]

## calculate the QC metrics
sexbranchWT<-calculateQCMetrics(sexbranchWT)

## set up the colour pal
nb.cols <- 18 
mycolors <- colorRampPalette(brewer.pal(9, "Set1"))(nb.cols)

Calculate the PCS

## calculate PCA
pca <- prcomp(t(assays(sexbranchWT)$counts), scale. = FALSE)

## subset coordinates
rd1 <- pca$x[,1:2]

## plot
plot(rd1, col = rgb(0,0,0,.5), pch=16, asp = 2)

## cluster using kmeans
## you need to set a seed here to ensure the results are reproducible
set.seed(42)
cl2 <- kmeans(rd1, centers = 13)$cluster

## plot
plot(rd1, col = mycolors[cl2], asp = 3, pch = 16)

## make a nicer plot so we can interpret the clusters
df_plotting <- as.data.frame(cbind(rd1, cl2))
## change to character to make it discrete
df_plotting$cl2 <- as.character(df_plotting$cl2)
## plot
ggplot(df_plotting, aes(x = PC1, y = PC2, colour = cl2)) + 
  geom_point() + 
  scale_colour_manual(values = rainbow(13)) + 
  theme_classic()
## initialise plot to prevent error
plot.new()

## slingshot to get lineages
lin1 <- getLineages(rd1, cl2,start.clus = '8')

## make a curve through lineage 
crv1 <- getCurves(lin1)

## join points with line segments and plot
plot(rd1, col = mycolors[cl2], asp = 3, pch = 16)
lines(crv1, lwd = 3, col = 'black')

## add PCA coordinates to SCE object
reducedDims(sexbranchWT) <- SimpleList(PCA = rd1)

## add clusters to SCE object
sexbranchWT$GMM<-cl2

## Add pseudotimes to SCE object
sexbranchWT$PT_LineageFemale<-as.data.frame(slingPseudotime(crv1))$curve1
sexbranchWT$PT_LineageMale<-as.data.frame(slingPseudotime(crv1))$curve2

## add designation to SCE object
sexbranchWT$male<-is.na(sexbranchWT$PT_LineageFemale)
sexbranchWT$female<-is.na(sexbranchWT$PT_LineageMale)
vec <- vector()
for (i in 1:length(sexbranchWT$male)) {
if (sexbranchWT$male[i] == sexbranchWT$female[i]) {vec<-c(vec,"pre-det")}
  if (sexbranchWT$male[i] == TRUE) {vec<-c(vec,"male")}
  if (sexbranchWT$female[i] == TRUE) {vec<-c(vec,"female")}  
}

sexbranchWT$sex<-vec

## plot coloured by NEK3 (PBANKA_0600600)
plotPCA(sexbranchWT,shape_by="sex",colour_by="PBANKA-0600600")

slingshot on UMAP

## extracts only 10x cells 
wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = wt_cells)

## get UMAP coordinates
umap_coords <- seurat.object@reductions$umapoptimised_post_repca@cell.embeddings

## get clusters
#clusters <- as.list(seurat.object@meta.data$integrated_snn_res.4)
#names(clusters) <- rownames(seurat.object@meta.data)
#clusters <- as.list(clusters)
## cluster using kmeans
## you need to set a seed here to ensure the results are reproducible
set.seed(42)
clusters <- kmeans(umap_coords, centers = 13)$cluster

## plot
## make a nicer plot so we can interpret the clusters
df_plotting <- as.data.frame(cbind(umap_coords, clusters))
## change to character to make it discrete
df_plotting$clusters <- as.character(df_plotting$clusters)
## plot
ggplot(df_plotting, aes(x = umapoptimised_1, y = umapoptimised_2, colour = clusters)) + 
  geom_point() + 
  scale_colour_manual(values = rainbow(15)) + 
  theme_classic()


## initialise plot to prevent error
plot.new()

## slingshot to get lineages
lineage_uamp <- getLineages(umap_coords, clusters, start.clus = '6', end.clus = c('1', '12'))

## make a curve through lineage 
crv1 <- getCurves(lineage_uamp)

## join points with line segments and plot
plot(umap_coords, col = mycolors[clusters], asp = 3, pch = 16)
lines(crv1, lwd = 3, col = 'black')

Add data to Seurat:

## extract data to add to Seurat
## extract clusters
meta_data_to_add_from_slingshot <- data.frame(clusters_k_means_UMAP = clusters)
## Add pseudotimes
# check the length of each branch to see which curve is which using: sum(is.na(as.data.frame(slingPseudotime(crv1))$curve1))
# then inspect using the ggplot2 above to where males are - 
# tail(as.data.frame(slingPseudotime(crv1)), 100)
# tail(meta_data_to_add_from_slingshot, 100)
meta_data_to_add_from_slingshot$PT_Female_UMAP <- as.data.frame(slingPseudotime(crv1))$curve1
meta_data_to_add_from_slingshot$PT_Male_UMAP <- as.data.frame(slingPseudotime(crv1))$curve2
## add designation to SCE object
meta_data_to_add_from_slingshot$sex_UMAP <- "pre-det"
meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Female_UMAP))] <- "male"
meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Male_UMAP))] <- "female"

## if there are 3 curves in slingPseudotime(crv1):
#meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Female_UMAP) & is.na(as.data.frame(slingPseudotime(crv1))$curve3))] <- "male"
#meta_data_to_add_from_slingshot$sex_UMAP[which(is.na(meta_data_to_add_from_slingshot$PT_Male_UMAP) & is.na(as.data.frame(slingPseudotime(crv1))$curve3))] <- "female"

## add clusters to SCE object
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, meta_data_to_add_from_slingshot)
## plot
FeaturePlot(tenx.mutant.integrated.sex, label.size = 5, pt.size = 0.5, features = c("PT_Female_UMAP", "PT_Male_UMAP")) +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

plot sex designations

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "sex_UMAP", na.value = "white") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

SCMAP

Load package

library(scmap)

Set up Index

#the reference dataset is: sexbranchWT
## set up a feature symbol column in the SCE object
rowData(sexbranchWT)$feature_symbol <- rownames(sexbranchWT)

## make an is_expr assay which only counts values with more than 0
assay(sexbranchWT, "is_expr") <- counts(sexbranchWT) > 0

## Select the top 500 most important genes
sexbranchWT <- selectFeatures(sexbranchWT, suppress_plot = FALSE, n_features = 500)

## inspect features selected
table(rowData(sexbranchWT)$scmap_features)

## create reference index
sexbranchWT <- indexCell(sexbranchWT)

## inspect results
names(metadata(sexbranchWT)$scmap_cell_index)
length(metadata(sexbranchWT)$scmap_cell_index$subcentroids)
dim(metadata(sexbranchWT)$scmap_cell_index$subcentroids[[1]])

Query dataset

#query data set is called: sexbranch
z <- sexbranch

## add feature symbol to SCE object
rowData(z)$feature_symbol <- rownames(z)

## map cells
scmapCell_results <- scmapCell(z, list(yan = metadata(sexbranchWT)$scmap_cell_index))

## copy over PCA coordinate
colData(sexbranchWT)$PC1<-as.data.frame(reducedDim(sexbranchWT))$PC1
colData(sexbranchWT)$PC2<-as.data.frame(reducedDim(sexbranchWT))$PC2

## Get nearest cell - which is located in the first row and make a list
getcells <- scmapCell_results$yan$cells[1, ]
## Extract meta data for these cells
cdsce <- colData(sexbranchWT)[getcells, ]
## Get similarity scores
topsim <- scmapCell_results$yan$similarities[1, ]

## add meta data to query dataset
# add nearest cell
z$top_pbcell <- getcells
## add PCA coordinates
z$PC1 <- cdsce$PC1
z$PC2 <- cdsce$PC2
## add assigned sex
z$sex<- cdsce$sex
## add pt
z$PT_LineageFemale<- cdsce$PT_LineageFemale
z$PT_LineageMale<- cdsce$PT_LineageMale
## add similarity score
z$topsim <- topsim

## inspect similarity scores
hist(z$topsim)

## count anything with a similarity score below 0.4 as unassigned
z$topcell_sp[z$topsim < 0.4] <- "unassigned"
z$topcell_sp <- as.factor(z$topcell_sp)
z$yt<-rep("assigned",length(z$topcell_sp))
z$yt[z$topsim < 0.4] <- "unassigned"

## extract PC scores
no <- as.data.frame(reducedDim(sexbranchWT)[,1:2])
## extract meta data
number2 <- as.data.frame(cdsce)
## extract top cell
number2$topcell_sp <- z$yt

## plot
ggplot(no, aes(PC1, PC2)) +
 geom_point(size = 1,alpha = 1/10) +
 geom_point(aes(x=PC1, y=PC2,shape=factor(topcell_sp)), data=number2, size=2, colour="black") +
 theme_classic() + scale_shape_manual(values=c(1,2))+
 scale_color_manual( values = c("0" = "#1f77b4","1" ="#ff7f0e","2" ="#2ca02c","3,0" ="#d62728","3,1" ="#9467bd","3,2"="#8c564b","3,3"="#e377c2","4"="#bcbd22","5"="#17becf","6"="#aec7e8")) + labs(x="PC1", y="PC2") 

#+
#  theme(legend.position="none", axis.title=element_text(size=8), legend.text = element_text(size = , legend.title = element_text(size #= 8), axis.text = element_text(size=:sunglasses:, axis.text.x = element_blank(), axis.text.y = element_blank())

to skip this section above and just get the data output from Arthur’s script where PCA is used as the base dimensionality reduction:

read in Arthur’s data

## read in data
at_data <- readRDS("~/data/sexbranch")

## extract values of interest
at_meta_data <- as.data.frame(at_data@colData)

## look at new cols:
head(table(at_meta_data$top_pbcell))
head(table(at_meta_data$topsim))
head(table(at_meta_data$topcell_sp))
head(table(at_meta_data$yt))
head(table(at_meta_data$sex))
#table(at_meta_data$PT_LineageFemale)
#table(at_meta_data$PT_LineageMale)

Add meta data to Seurat object

colnames_to_add_to_meta_data <- c("top_pbcell", "topsim", "topcell_sp", "yt", "sex", "PT_LineageFemale", "PT_LineageMale")

tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, metadata = at_meta_data[,which(colnames(at_meta_data) %in% colnames_to_add_to_meta_data)], col.name = c("at_top_pbcell", "at_topsim", "at_topcell_sp", "at_yt", "at_sex", "at_PT_LineageFemale", "at_PT_LineageMale"))

## to remove columns in metadata:
#tenx.mutant.integrated.sex@meta.data[136:144] <- NULL
#tenx.mutant.integrated.sex@meta.data[['NAME_OF_COL']] <- NULL

Plot sexes

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "at_sex") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))
## the slingshot pt values have NAs for e.g. male cells in the PT_LineageFemale, we can deal with this later, but for now, we will just ignore this as Dimplot will not plot NA values
#sum(is.na(tenx.mutant.integrated.sex@meta.data$at_PT_LineageMale))
#sum(is.na(tenx.mutant.integrated.sex@meta.data$at_PT_LineageFemale))

## plot
FeaturePlot(tenx.mutant.integrated.sex, label.size = 5, pt.size = 0.5, features = c("at_PT_LineageFemale", "at_PT_LineageMale")) +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Comparison of cluster way of calling males and females vs. slingshot:

table(tenx.mutant.integrated.sex@meta.data$sex)

male_clusters <- c("13", "5", "11", "25", "1", "17", "10", "24", "14", "27", "19")
female_clusters <- c("16", "22", "23", "15", "21", "30", "4", "3", "18", "7", "8", "6", "20", "12", "26")
asex_clusters <- c("0", "9", "28", "2", "29")

tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters <- NA
tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters %in% male_clusters)] <- "Male"
tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters %in% female_clusters)] <- "Female"
tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters[which(tenx.mutant.integrated.sex@meta.data$seurat_clusters %in% asex_clusters)] <- "Pre-det"

table(tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters)
table(tenx.mutant.integrated.sex@meta.data$sex, tenx.mutant.integrated.sex@meta.data$sex_designation_using_clusters)

Plot sexes

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "sex") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

Plot sexes

DimPlot(tenx.mutant.integrated.sex, label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "sex_designation_using_clusters") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))

correlation of monocle PT and

## extract pseudotime values:
pt_values <- as.data.frame(pseudotime(monocle.object, reduction_method = "UMAP"))
pt_values$cell_name <- rownames(pt_values)
meta_data_df <- as.data.frame(monocle.object@colData)
meta_data_df$cell_name <- rownames(meta_data_df)
meta_data_df <- merge(meta_data_df, pt_values, by = "cell_name")
names(meta_data_df)[142]<- "pt"

male_pt_correlation_df <- meta_data_df[which(meta_data_df$cell_name %in% male_cells), ]
female_pt_correlation_df <- meta_data_df[which(meta_data_df$cell_name %in% female_cells), ]

ggplot(male_pt_correlation_df, aes(x = PT_LineageMale, y = pt, colour = sex)) + 
  geom_point() +  
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic()

ggplot(female_pt_correlation_df, aes(x = PT_LineageFemale, y = pt, colour = sex)) + 
  geom_point() + 
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic()
ggplot(male_pt_correlation_df, aes(x = PT_Female_UMAP, y = pt)) + 
  geom_point() +  
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic()

6. Monocle on sex cells

calculate pseudotime and modules

Preparation

## load package
#library(monocle3)

## help was obtained from here
## https://github.com/satijalab/seurat/issues/1658

## extract data
## this extracts wt only cells
#wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" | tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"),])

## extracts only 10x cells 
wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = wt_cells)

## make new counts and pheno:
## the reason we use the integrated and then subsetted is because these cells have been normalised whereas the cells in pb_sex_filtered have not been normalised (well they have but with doublets in them)
data <- as(as.matrix(GetAssayData(seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(seurat.object@meta.data)

## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)

## preprocess
monocle.object = preprocess_cds(monocle.object, num_dim = 50, norm_method = "none")
### if using integrated data:
# norm_method = "none", alignment_group = "~ experiment"

plot_pc_variance_explained(monocle.object)

monocle.object = reduce_dimension(monocle.object, reduction_method = "UMAP", preprocess_method = "PCA", umap.metric = "euclidean", umap.n_neighbors = 50, umap.min_dist = 0.5, verbose = FALSE)

plot_cells(monocle.object, color_cells_by="experiment")

Graph Learning

## add UMAP from Seurat
monocle.object@int_colData@listData$reducedDims@listData[["UMAP"]] <- seurat.object@reductions[["umap"]]@cell.embeddings

## cluster
monocle.object = cluster_cells(monocle.object)

## plot
plot_cells(monocle.object, color_cells_by="cluster", group_cells_by="partition")

## map pseudotime
monocle.object = learn_graph(monocle.object, learn_graph_control=list(ncenter=400), use_partition = FALSE)
# learn_graph_control=list(ncenter=500) - play with this parameter

## Plot cells
plot_cells(monocle.object, color_cells_by="partition", group_cells_by="partition") 

Pseudotime Calculation

## a helper function to identify the root principal points:
get_earliest_principal_node <- function(cds, time_bin="0"){
  cell_ids <- which(colData(cds)[, "seurat_clusters"] == time_bin)
  closest_vertex <-
  cds@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex
  closest_vertex <- as.matrix(closest_vertex[colnames(cds), ])
  root_pr_nodes <-
  igraph::V(principal_graph(cds)[["UMAP"]])$name[as.numeric(names
  (which.max(table(closest_vertex[cell_ids,]))))]
  
  root_pr_nodes
}

## Order the cells and caclulate pseudotime
monocle.object = order_cells(monocle.object, root_pr_nodes=get_earliest_principal_node(monocle.object))

## Plot
plot_cells(monocle.object, color_cells_by = "pseudotime", label_cell_groups=FALSE, cell_size = 2) +
  coord_fixed() +
  theme_void() +
  labs(title = "Pseudotime") +
  theme(plot.title = element_text(hjust = 0.5))

Check how well it correlates with the original pseudotime

when pseudotime was calcualted on the whole object

library(ggpubr)
## extract pseudotime values:
pt_values_new <- as.data.frame(pseudotime(monocle.object, reduction_method = "UMAP"))
pt_values_new$cell_name <- rownames(pt_values_new)
meta_data_df <- as.data.frame(monocle.object@colData)
meta_data_df$cell_name <- rownames(meta_data_df)
meta_data_df <- merge(meta_data_df, pt_values_new, by = "cell_name")
names(meta_data_df)[145]<- "pt"

ggplot(meta_data_df, aes(x = old_pt_values, y = pt, colour = sex_UMAP)) + 
  geom_point() +  
  geom_smooth(method = "lm", se = FALSE) +
  theme_classic() + stat_cor(method = "pearson")

Isolate Branches

## access the closest principal graph node vertex for each cell and assign it as a column in your colData table using
colData(monocle.object)$closest_vertex <- monocle.object@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex[,1]

## plot
plot_cells(monocle.object, color_cells_by = "closest_vertex", label_cell_groups = FALSE)

Module Construction

## find genes that change as a function of pt:
monocle.object_pr_test_res <- graph_test(monocle.object, neighbor_graph="principal_graph", cores=8)

## find significant genes
pr_deg_ids <- row.names(subset(monocle.object_pr_test_res, q_value < 0.01))

## collect into modules
gene_module_df_sex <- find_gene_modules(monocle.object[pr_deg_ids,], resolution=c(10^seq(-6,2)))

## how many genes in modules?
dim(gene_module_df_sex)

Plot Modules

General Module Characteristics

Make a dataframe to plot by aggregating clusters vs. modules

## make cell group df
cell_group_df <- tibble::tibble(cell=row.names(colData(monocle.object)), cell_group=colData(monocle.object)$seurat_clusters)

## make plotting df
agg_mat <- aggregate_gene_expression(monocle.object, gene_module_df_sex, cell_group_df)

Find out how many genes there are per total so we can add this to the plot

## how many genes per module?
genes_per_module <- as.data.frame(table(gene_module_df_sex$module))
genes_per_module

Find out which modules our mutant genes reside in

## create a list of our mutant gene IDs
list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

## make a dataframe to convert the gene IDs into actual IDs
df_mutant_ids <- as.data.frame(unique(cbind(tenx.mutant.integrated@meta.data$identity_gene_updated, tenx.mutant.integrated@meta.data$identity_updated)))[-c(1, 4),]
# remove the "820" bit on 10
df_mutant_ids$V1 <- gsub("_820", "", df_mutant_ids$V1)
# change the underscore (_) to a dash (-) in gene IDs
df_mutant_ids$V1 <- gsub("_", "-", df_mutant_ids$V1)
names(df_mutant_ids) <- c("gene_ID", "mutant_identity")

## subset modules df to include only mutant gene IDs
df_mutant_gene_modules <- as.data.frame(gene_module_df_sex[which(gene_module_df_sex$id %in% list_of_mutant_genes),])
names(df_mutant_gene_modules)[1] <- "gene_ID"

## merge dataframes
df_mutant_gene_modules <- merge(df_mutant_gene_modules, df_mutant_ids, by = "gene_ID")

## Inspect
df_mutant_gene_modules

so modules of interest are:

table(df_mutant_gene_modules$module)

Which modules do other genes of interest lie in?:

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
# ccp2 - "PBANKA-1319500" - female 820
# MG1 - "PBANKA-0416100" - male 820

## create a list of landmark genes
list_of_landmark_genes <- c("PBANKA-1437500", "PBANKA-0909600","PBANKA-1034300", "PBANKA-1319500", "PBANKA-0416100")

## make dataframe
df_landmark_gene_modules <- gene_module_df_sex[which(gene_module_df_sex$id %in% list_of_landmark_genes),]

## inspect
df_landmark_gene_modules

plot out modules

## make aggregated df again so you can edit it
agg_mat <- aggregate_gene_expression(monocle.object, gene_module_df_sex, cell_group_df)

## h clust the aggregated matrix
module_dendro <- hclust(dist(agg_mat))

## use these clusters to reorder the modules
gene_module_df_sex$module <- factor(gene_module_df_sex$module, levels = row.names(agg_mat)[module_dendro$order])

## plot
plot_cells(monocle.object, genes=gene_module_df_sex %>% filter(module %in% c(1:20)),
                          label_cell_groups=FALSE,
                          scale_to_range = TRUE,
                          show_trajectory_graph=FALSE,
                          group_label_size = 8) +
                          scale_colour_viridis_c(name = "expression", option = "C", alpha = 1) +
                          coord_fixed() +
                          theme_void() +
                          theme(legend.position = "bottom")
## make a dataframe of genes per module
genes_per_module <- as.data.frame(table(gene_module_df_sex$module))

Make annotations to add to the heatmap

## change names for row names to include "module " at the begining of them
row.names(agg_mat) <- stringr::str_c("Module ", row.names(agg_mat))

## add number of cells to the rownames for the module
for(i in seq_along(genes_per_module$Freq)){
  row.names(agg_mat)[i] <- stringr::str_c(row.names(agg_mat)[i]," (n = " ,genes_per_module$Freq[i], ")")
}

## create annotation of clusters for pheatmap:
cluster_anno <- data.frame(cluster = unique(colData(monocle.object)$seurat_clusters))
row.names(cluster_anno) <- cluster_anno$cluster

## clusters were defined earlier as:
male_clusters <- c("13", "5", "11", "25", "1", "17", "10", "24", "14", "27", "19")
female_clusters <- c("16", "22", "23", "15", "21", "30", "4", "3", "18", "7", "8", "6", "20", "12", "26")
asex_clusters <- c("0", "9", "28", "2", "29")

## add identities to the column
cluster_anno$group <- NA
cluster_anno$group[which(cluster_anno$cluster %in% asex_clusters)] <- "Asexual"
cluster_anno$group[which(cluster_anno$cluster %in% male_clusters)] <- "Male"
cluster_anno$group[which(cluster_anno$cluster %in% female_clusters)] <- "Female"
cluster_anno <- cluster_anno[ , 2, drop = FALSE]
cluster_anno

## add median pseudotime per cluster
## help here:
## https://stackoverflow.com/questions/54360855/calculate-mean-for-column-grouped-by-values-of-two-other-columns
## make subsetted dataframe
df_median_pt <- meta_data_df[ ,c("pt", "seurat_clusters")]
## apply across dataframe to get median
mean.df1 <- tapply(df_median_pt$pt, list(df_median_pt$seurat_clusters), median)
mean.df2 <- as.data.frame(as.table(mean.df1))
names(mean.df2) <- c("seurat_clusters", "pt_Median")
rownames(mean.df2) <- mean.df2$seurat_clusters
## to make each value have the mean in the OG dataframe
#merge(df_median_pt, mean.df2)
## add to annotation dataframe
cluster_anno <- merge(cluster_anno, mean.df2, by=0)

## add rownames to dataframe
rownames(cluster_anno) <- cluster_anno$Row.names
## subset to have only info of interest
cluster_anno <- cluster_anno[,c(2,4)]
names(cluster_anno) <- c("Identity", "Median_Pseudotime_of_Cluster")

WT cells by modules over pt (central panel)

## make annotation colours
annotation_colours <- list(Identity = c(Male="#016c00", Female="#a52b1e", Asexual= "#0052c5"),
                           Median_Pseudotime_of_Cluster = magma(12, direction = 1))

## reorder the levels
## make df of data
agg_mat_df <- as.data.frame(agg_mat)
## remove levels in my_levels that are not present here - i.e. clusters that are missing because they are not represented in the 10X data
my_levels_10x_data <- my_levels_sex[which(my_levels_sex %in% colnames(agg_mat_df))]
## sort the values
agg_mat_df <- agg_mat_df[ ,(match(my_levels_10x_data, colnames(agg_mat_df)))]

## order 
#cluster_anno <- cluster_anno[(match(my_levels_10x_data, rownames(cluster_anno))), ]

## reorder columns 
## first, order the annotation
cluster_anno <- cluster_anno[with(cluster_anno, order(Identity, Median_Pseudotime_of_Cluster)),]

## remove the NAs from this
cluster_anno <- cluster_anno[complete.cases(cluster_anno),]

agg_mat_df <- agg_mat_df[ ,match(rownames(cluster_anno), colnames(agg_mat_df))]

## plot heatmap
pheatmap::pheatmap(agg_mat_df, 
                   scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2", 
                   annotation_col = cluster_anno, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

#, gaps_col = c(28,29,37)
#row.names(agg_mat) <- factor(row.names(agg_mat), levels = row.names(agg_mat)[module_dendro$order])

## plot heatmap
#pheatmap::pheatmap(agg_mat_df, 
  #                  scale="column",
  #                  cluster_cols = TRUE,
  #                  cluster_rows = module_dendro,
  #                  #clustering_method="ward.D2",
  #                  cutree_rows = 5,
  #                  annotation_col = cluster_anno, 
  #                  annotation_colors = annotation_colours) + 
  # theme(legend.position = "bottom")

All Cells

Pheatmap version

## prepare custom dataframe for all cells by modules:
agg_mat_no_group <- aggregate_gene_expression(monocle.object, gene_module_df_sex)

## make an anotation
anno_no_group <- data.frame(monocle.object@colData$sex_UMAP, monocle.object@colData$old_pt_values, row.names = rownames(monocle.object@colData))
names(anno_no_group) <- c("sex", "Pseudotime")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order <- rownames(anno_no_group[with(anno_no_group, order(sex, Pseudotime)), ])
agg_mat_no_group <- agg_mat_no_group[,col.order]

## plot
pheatmap::pheatmap(agg_mat_no_group, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

Now rearrange the cols so that it is in a better order

## extract each group of cells in the correct order for plotting
## order the annotation data frame
ordered_cells <- anno_no_group[with(anno_no_group, order(sex, Pseudotime)), ]
## extract the cells in their new order
female_ordered_cells <- rownames(ordered_cells[which(ordered_cells$sex == "female"), ])
male_ordered_cells <- rownames(ordered_cells[which(ordered_cells$sex == "male"), ])
pre_det_ordered_cells <- rownames(ordered_cells[which(ordered_cells$sex == "pre-det"), ])
col.order <- c(pre_det_ordered_cells, female_ordered_cells, male_ordered_cells)
##check
#length(col.order)
#dim(agg_mat_no_group)

## reorder using new order
agg_mat_no_group <- agg_mat_no_group[,col.order]

## reorder the rows
## define the order visually and using the clusters originally produced
row.order <- c("5", "4", "13", "11", "6", "2", "7", "3", "8", "17", "9", "16", "14", "12", "15", "1", "10")

## reorder using new order
agg_mat_no_group <- agg_mat_no_group[row.order, ]

## add module and the number of cells to the row
## change names for row names to include "module " at the begining of them
labels.row <- stringr::str_c("Module ", row.names(agg_mat_no_group))
## reorder frequency so that it is matching our matrix
genes_per_module_ordered <- genes_per_module[match(row.names(agg_mat_no_group), genes_per_module$Var1), ]
## add number of cells to the rownames for the module
for(i in seq_along(genes_per_module_ordered$Freq)){
  labels.row[i] <- stringr::str_c(labels.row[i]," (n = " ,genes_per_module_ordered$Freq[i], ")")
}

## plot
heatmap_main <- pheatmap::pheatmap(agg_mat_no_group, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   labels_row = labels.row,
                   gaps_col = c(length(pre_det_ordered_cells), length(pre_det_ordered_cells) + length(female_ordered_cells)),
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

heatmap_main

Plot specific genes of interest

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
#list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

list_of_genes_of_interest <- c("PBANKA-0102400", "PBANKA-0413400", "PBANKA-0716500", "PBANKA-0828000", "PBANKA-0902300", "PBANKA-1144800", "PBANKA-1302700", "PBANKA-1418100", "PBANKA-1435200", "PBANKA-1447900", "PBANKA-1454800", "PBANKA-1437500", "PBANKA-1319500", "PBANKA-0416100")
names_of_genes_of_interest <- c("GCSKO-2", "GCSKO-10", "GCSKO-19", "GCSKO-3", "GCSKO-13", "GCSKO-28", "GCSKO-oom", "GCSKO-17", "GCSKO-20", "GCSKO-29", "GCSKO-21", "AP2-G", "CCP2", "MG1")
##make df for genes of interest
genes_of_interest <- data.frame(gene = list_of_genes_of_interest, group = c(1:length(list_of_genes_of_interest)), name = names_of_genes_of_interest)
## reorder
#genes_of_interest <- genes_of_interest[match(c("AP2-G", "CCP2", "GCSKO-21", "GCSKO-17", "GCSKO-2", "MG1", "GCSKO-20", "GCSKO-3", "GCSKO-oom", "GCSKO-29", "GCSKO-10", "GCSKO-28", "GCSKO-19", "GCSKO-13"), genes_of_interest$name), ]

## prepare custom dataframe for all cells by modules:
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest[,1:2])

## reorder using new order
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[,col.order]

## plot
heatmap_plot <- pheatmap::pheatmap(agg_mat_genes_of_interest, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = TRUE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   labels_row = as.character(genes_of_interest[,3]),
                   gaps_col = c(length(pre_det_ordered_cells), length(pre_det_ordered_cells) + length(female_ordered_cells)),
                   #gaps_row = c(1, 6),
                   cutree_rows = 2,
                   ## trying to fix legend issue here
                   #fontsize_row = 10,
                   #fontsize_col = 3,
                   #cellheight=3, 
                   #cellwidth = 3,
                   legend = TRUE,
                   annotation_legend = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours
                   )

heatmap_plot

Side plots

construct new dataframes for the cells from mutants for each sex

## The original object contains all cells, we just want wild-type so let's subset out gene_module_df and cell_group_df accordingly

## male
## subset out only male and pre determination cells
male_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$at_sex == "male"), ]
## take forward only smart-seq2
male_cells <- male_cells[which(male_cells$experiment == "mutants"), ]
## get cell names
male_cells <- rownames(male_cells)
## subset Seurat object to contain cells of interest  
male.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = male_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(male.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(male.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
male.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
male.monocle.object = preprocess_cds(male.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
#male_cell_group_df <- data.frame(cell=as.character(factor(male_cell_group_df$cell_id)), cell_group=factor(male_cell_group_df$pt_bin))  
## aggregate expression
male_agg_mat <- aggregate_gene_expression(male.monocle.object, gene_module_df_sex, exclude.na = FALSE)

## female
## subset out only male and pre determination cells
female_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$at_sex == "female"), ]
## take forward only wild-type
female_cells <- female_cells[which(female_cells$experiment == "mutants"), ]
## get cell names
female_cells <- rownames(female_cells)
## subset our cell group df to keep only these cells
#female_cell_group_df <- female_cell_group_df[which(female_cell_group_df$cell_id %in% female_cells),]
## subset Seurat object to contain cells of interest  
female.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = female_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(female.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(female.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
female.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
female.monocle.object = preprocess_cds(female.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
#female_cell_group_df <- data.frame(cell=as.character(factor(female_cell_group_df$cell_id)), cell_group=factor(female_cell_group_df$pt_bin))  
## aggregate expression
female_agg_mat <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, exclude.na = FALSE)

male

# male_agg_mat
## reorder using new order
male_agg_mat <- male_agg_mat[row.order, ]

## make an anotation
anno_male <- data.frame(male.monocle.object@colData$at_sex, male.monocle.object@colData$old_pt_values, genotype = male.monocle.object@colData$identity_updated, row.names = rownames(male.monocle.object@colData))
names(anno_male) <- c("sex", "Pseudotime", "genotype")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order.male <- rownames(anno_male[with(anno_male, order(genotype, Pseudotime)), ])
male_agg_mat <- male_agg_mat[,col.order.male]

## plot
heatmap_male <- pheatmap::pheatmap(male_agg_mat, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   legend = FALSE,
                   annotation_legend = TRUE,
                   annotation_col = anno_male, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

heatmap_male
# female_agg_mat
## reorder using new order
female_agg_mat <- female_agg_mat[row.order, ]

## make an anotation
anno_female <- data.frame(female.monocle.object@colData$at_sex, female.monocle.object@colData$old_pt_values, genotype = female.monocle.object@colData$identity_updated, row.names = rownames(female.monocle.object@colData))
names(anno_female) <- c("sex", "Pseudotime", "genotype")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order.female <- rownames(anno_female[with(anno_female, order(genotype, Pseudotime)), ])
female_agg_mat <- female_agg_mat[,col.order.female]

## plot
heatmap_female <- pheatmap::pheatmap(female_agg_mat, 
                   #scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   legend = FALSE,
                   annotation_legend = FALSE,
                   annotation_col = anno_female, 
                   annotation_colors = annotation_colours, 
                   cutree_rows = 12)

heatmap_female

## save a pheatmap: https://stackoverflow.com/questions/43051525/how-to-draw-pheatmap-plot-to-screen-and-also-save-to-file

side plots with groups of mutant cells

female

## make a new grouping for cells based on their identity
mutant_group_female <- data.frame(cell = rownames(female.monocle.object@colData), cell_group = female.monocle.object@colData$identity_updated)

## aggregate expression
female_agg_mat_grouped <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, mutant_group_female, exclude.na = FALSE)

## reorder using new order
female_agg_mat_grouped <- female_agg_mat_grouped[row.order, ]

## plot
pheatmap::pheatmap(female_agg_mat_grouped, 
                   #scale="row",
                   cluster_cols = TRUE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = TRUE,
                   legend = FALSE,
                   annotation_legend = FALSE,
                   #annotation_col = anno_female, 
                   #annotation_colors = annotation_colours, 
                   cutree_rows = 12)

male

module 12 inspection

## make a df for module 12 genes
module.12.genes <- gene_module_df_sex[gene_module_df_sex$module == 12, ]$id
module.12.genes <- data.frame(id = module.12.genes, group = module.12.genes)

## prepare custom dataframe for all cells by modules:
agg_mat_module_12 <- aggregate_gene_expression(monocle.object, module.12.genes)

## make an anotation
anno_no_group <- data.frame(monocle.object@colData$sex_UMAP, monocle.object@colData$old_pt_values, row.names = rownames(monocle.object@colData))
names(anno_no_group) <- c("sex", "Pseudotime")

## make annotation colours
annotation_colours <- list(sex = c(male="#016c00", female="#a52b1e", 'pre-det' = "#0052c5"),
                           Pseudotime = magma(12, direction = 1))

## change the order of the data frame
col.order <- c(pre_det_ordered_cells, female_ordered_cells, male_ordered_cells)
agg_mat_module_12 <- agg_mat_module_12[,col.order]

## plot
pheatmap::pheatmap(agg_mat_module_12, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours,
                   fontsize_row = 7,
                   cutree_rows = 12)

save plot

heatmap_module_12 <- pheatmap::pheatmap(agg_mat_module_12, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="ward.D2",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours,
                   fontsize_row = 7,
                   cutree_rows = 12)

AP2 Expression

## reading table of AP2 genes
ap2_genes_table <- read.delim(file = "~/data/AP2_genes_table.txt", header = TRUE, sep ="\t")

## extract list of genes
ap2_genes_list <- dplyr::pull(ap2_genes_table, Gene.ID)
ap2_genes_list <- gsub("_", "-", ap2_genes_list)

## make a df for genes
ap2_genes_list <- data.frame(id = ap2_genes_list, group = ap2_genes_list)

## prepare custom dataframe for all cells by modules:
agg_mat_ap2s <- aggregate_gene_expression(monocle.object, ap2_genes_list)

## change the order of the data frame
col.order <- c(pre_det_ordered_cells, female_ordered_cells, male_ordered_cells)
agg_mat_ap2s <- agg_mat_ap2s[,col.order]

## plot
pheatmap::pheatmap(agg_mat_ap2s, 
                   #scale="row",
                   cluster_cols = FALSE,
                   clustering_method="complete",
                   show_colnames = FALSE,
                   annotation_col = anno_no_group, 
                   annotation_colors = annotation_colours,
                   fontsize_row = 7,
                   cutree_rows = 3)

Module Analysis

Read in Kasia’s modules:

## read in kasia modules:
kasia_clusters <- read.csv(file = "~/data/Modules_Clusters_Phenotypes.csv", header = TRUE)

## change _ to -:
kasia_clusters$new.gene.ID <- gsub("_", "-", kasia_clusters$new.gene.ID)

## filter out genes not in modules gene_module_df_sex:
kasia_clusters_filtered <- kasia_clusters[which(kasia_clusters$new.gene.ID %in% gene_module_df_sex$id), ]

## rename new gene id
names(kasia_clusters_filtered)[2] <- "id"

## merge together
modules_merged_df <- merge(kasia_clusters_filtered, gene_module_df_sex, by = "id")

## look at the enrichment with a dotplot:
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(modules_merged_df$Kasia.Cluster, df_meta_data$identity_combined), margin = 2)) * 100)

NOT USED complex heatmap version

## make into matrix to plot
col.order <- agg_mat_all_cells_matrix <- as.matrix(agg_mat_all_cells)

make annotation

## extract pseudotime values:
pt_values <- as.data.frame(pseudotime(monocle.object, reduction_method = "UMAP"))
names(pt_values) <- "monocle_pt_sex_wt"
tenx.mutant.integrated.sex <- AddMetaData(tenx.mutant.integrated.sex, pt_values)

## save pt values
write.csv(pt_values, file = "~/data_to_export/pt_values_sex_only.csv")
library(circlize)
## make the annotation df
## get meta data from seurat object and then subset rows out that are wt
df_anno <- tenx.mutant.integrated.sex@meta.data[which(rownames(tenx.mutant.integrated.sex@meta.data) %in% colnames(agg_mat_all_cells_matrix)), ]
## get only columns of interest:
df_anno <- df_anno[ ,c("sex", "monocle_pt_sex_wt"), drop = FALSE ]

## order annotation
df_anno <- df_anno[with(df_anno, order(sex, monocle_pt_sex_wt)),]

## order cols in the matrix
agg_mat_all_cells_matrix <- agg_mat_all_cells_matrix[ ,match(colnames(agg_mat_all_cells_matrix), rownames(df_anno))]

## make annotation
heatmap_annotation <- HeatmapAnnotation(df = cluster_anno, 
                                        col = list(sex = c(male="#016c00", female="#a52b1e", `pre-det` = "#0052c5"), monocle_pt_sex_wt = colorRamp2(c(1:70), inferno(70)))
                                        )

heatmap_annotation <- HeatmapAnnotation(sex = df_anno$sex, pt = df_anno$monocle_pt_sex_wt)

plot

## make heatmap
modules_heatmap <- Heatmap(agg_mat_all_cells_matrix,
        column_order = NULL,
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
## extract counts from 10x object
matrix_tenx_counts <- as.matrix(GetAssayData(pb_sex_filtered, assay = "RNA"))
#nk.raw.data <- as.matrix(GetAssayData(pb_sex_filtered, slot = "counts")[, WhichCells(pbmc, ident = "NK")])

## check it is the same as the merged object RNA slot

## check it is the same as the monocle object
matrix_tenx_counts_monocle <- as.matrix(as.data.frame((monocle.object@assays)))
## make heatmap
modules_heatmap <- Heatmap(matrix_tenx_counts,
        column_order = NULL,
        cluster_columns = TRUE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(matrix_tenx_counts)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        #bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

plot as a function of pseudotime

Now, we will integrate the branch data we produced using slingshot and the pseudotime values to plot this heatmap.

Monocle3 has a handy function that allows us to aggregate expression of groups of cells called aggregate_gene_expression.

The code for this is located here: https://github.com/cole-trapnell-lab/monocle3/blob/1a02274209c765fe7a60f533a31b1da3dacf6785/R/cluster_genes.R

Define the groups of cells

## Split cells into groups of sexes
female_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "female"), ]
male_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "male"), ]
pre_det_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det"), ]

## inspect range of pt values to determine bin width
hist(female_cells$PT_LineageFemale)
hist(male_cells$PT_LineageMale)
hist(pre_det_cells$PT_LineageFemale)
hist(pre_det_cells$PT_LineageMale)

Use a bin width of 2

there will be two objects for the cell_group_df: male branch and female branch. Both will include the pre-det branch

## Define male and female branch cells
# male
male_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "male"), ]

male_branch_meta_data <- data.frame(cell_id = rownames(male_branch_meta_data), pt = male_branch_meta_data$PT_LineageMale)

male_cell_group_df <- male_branch_meta_data

#female
female_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "female"), ]

female_branch_meta_data <- data.frame(cell_id = rownames(female_branch_meta_data), pt = female_branch_meta_data$PT_LineageFemale)

female_cell_group_df <- female_branch_meta_data

## what's the range of values for each pt?

range(female_cell_group_df$pt)
range(male_cell_group_df$pt)
## make bin widths
# make a new col for annotation
female_cell_group_df$pt_bin <- NA
for(i in seq(2,68,2)){
  female_cell_group_df$pt_bin[which(female_cell_group_df$pt < i & female_cell_group_df$pt >= (i-2))] <- i
}

male_cell_group_df$pt_bin <- NA
for(i in seq(2,68,2)){
  male_cell_group_df$pt_bin[which(male_cell_group_df$pt < i & male_cell_group_df$pt >= (i-2))] <- i
}
# then remove old pt values
male_cell_group_df <- male_cell_group_df[ ,-2]
female_cell_group_df <- female_cell_group_df[ ,-2]
## The original object contains all cells, we just want wild-type so let's subset out gene_module_df and cell_group_df accordingly

## male
## subset out only male and pre determination cells
male_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "male" | tenx.mutant.integrated.sex@meta.data$sex == "pre-det"), ]
## take forward only wild-type
male_cells <- male_cells[which(male_cells$identity_combined == "WT" | male_cells$identity_combined == "WT_10X"), ]
#male_cells <- male_cells[which(male_cells$identity_combined == "WT_10X"), ]
## get cell names
male_cells <- rownames(male_cells)
## subset our cell group df to keep only these cells
male_cell_group_df <- male_cell_group_df[which(male_cell_group_df$cell_id %in% male_cells),]
## subset Seurat object to contain cells of interest  
male.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = male_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(male.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(male.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
male.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
male.monocle.object = preprocess_cds(male.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
male_cell_group_df <- data.frame(cell=as.character(factor(male_cell_group_df$cell_id)), cell_group=factor(male_cell_group_df$pt_bin))  
## aggregate expression
male_agg_mat <- aggregate_gene_expression(male.monocle.object, gene_module_df_sex, male_cell_group_df, exclude.na = FALSE)

## female
## subset out only male and pre determination cells
female_cells <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "female" | tenx.mutant.integrated.sex@meta.data$sex == "pre-det"), ]
## take forward only wild-type
female_cells <- female_cells[which(female_cells$identity_combined == "WT" | female_cells$identity_combined == "WT_10X"), ]
#female_cells <- female_cells[which(female_cells$identity_combined == "WT_10X"), ]
## get cell names
female_cells <- rownames(female_cells)
## subset our cell group df to keep only these cells
female_cell_group_df <- female_cell_group_df[which(female_cell_group_df$cell_id %in% female_cells),]
## subset Seurat object to contain cells of interest  
female.seurat.object <- SubsetData(tenx.mutant.integrated.sex, cells = female_cells)
## make new counts and pheno:
data <- as(as.matrix(GetAssayData(female.seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(female.seurat.object@meta.data)
## keep only the columns that are relevant
#pData <- pd %>% select(orig.ident, nCount_RNA, nFeature_RNA)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))
## Construct monocle cds
female.monocle.object <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)
## preprocess
female.monocle.object = preprocess_cds(female.monocle.object, num_dim = 50, norm_method = "none")  
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
female_cell_group_df <- data.frame(cell=as.character(factor(female_cell_group_df$cell_id)), cell_group=factor(female_cell_group_df$pt_bin))  
## aggregate expression
female_agg_mat <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, female_cell_group_df, exclude.na = FALSE)
## use these clusters to reorder the modules
male_agg_mat <- male_agg_mat[match(levels(gene_module_df_sex$module), row.names(male_agg_mat)), ]
female_agg_mat <- female_agg_mat[match(levels(gene_module_df_sex$module), row.names(female_agg_mat)), ]

pheatmap::pheatmap(male_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(male_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(male_agg_mat, 
                   scale="none",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="none",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

ComplexHeatmap version

## pheatmap calculates Z scores for plotting values
scale_matrix_by_cols <- function (x) 
{
    m = apply(x, 1, mean, na.rm = T)
    s = apply(x, 1, sd, na.rm = T)
    return((x - m)/s)
}

## calculate z score by col
female_agg_mat_scaled <- t(as.matrix(scale_matrix_by_cols(t(female_agg_mat))))
male_agg_mat_scaled <- t(as.matrix(scale_matrix_by_cols(t(male_agg_mat))))
## reorder cols
female_agg_mat_scaled <- female_agg_mat_scaled[match(levels(gene_module_df_sex$module), row.names(female_agg_mat_scaled)), ]
male_agg_mat_scaled <- male_agg_mat_scaled[match(levels(gene_module_df_sex$module), row.names(male_agg_mat_scaled)), ]

## reorder based on clusters
genes_per_module <- genes_per_module[match(levels(gene_module_df_sex$module), row.names(genes_per_module)), ]

## change names for row names to include "module " at the begining of them
row.names(female_agg_mat_scaled) <- stringr::str_c("Module ", row.names(female_agg_mat_scaled))
row.names(male_agg_mat_scaled) <- stringr::str_c("Module ", row.names(male_agg_mat_scaled))

## add number of cells to the rownames for the module
for(i in seq_along(genes_per_module$Freq)){
  row.names(female_agg_mat_scaled)[i] <- stringr::str_c(row.names(female_agg_mat_scaled)[i]," (n = " ,genes_per_module$Freq[i], ")")
}
for(i in seq_along(genes_per_module$Freq)){
  row.names(male_agg_mat_scaled)[i] <- stringr::str_c(row.names(male_agg_mat_scaled)[i]," (n = " ,genes_per_module$Freq[i], ")")
}

## add annotation:
#heatmap_annotation <- HeatmapAnnotation(df = cluster_anno,
#                                         col = list(
# Identity = c(Male="#016c00", Female="#a52b1e", Asexual= "#0052c5", Committed = "#f2eb23")),
#                                         annotation_legend_param = list(Median_Pseudotime_of_Cluster = list(direction = "horizontal"), Identity = list(nrow = 1)))

library(ComplexHeatmap)
library(RColorBrewer)
modules_heatmap_female <- Heatmap(female_agg_mat_scaled,
        column_order = NULL,
        #row_order = row.names(female_agg_mat_scaled)[module_dendro$order],
        #clustering_method_rows = "ward.D2",
        #bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

modules_heatmap_male <- Heatmap(male_agg_mat_scaled,
        column_order = NULL,
        #row_order = module_dendro$order,
        #clustering_method_rows = "ward.D2",
        #bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

draw(modules_heatmap_female, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
draw(modules_heatmap_male, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

## https://www.biostars.org/p/380544/ 

4 bin width

## Define male and female branch cells
# male
male_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "male"), ]

male_branch_meta_data <- data.frame(cell_id = rownames(male_branch_meta_data), pt = male_branch_meta_data$PT_LineageMale)

male_cell_group_df <- male_branch_meta_data

#female
female_branch_meta_data <- tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "female"), ]

female_branch_meta_data <- data.frame(cell_id = rownames(female_branch_meta_data), pt = female_branch_meta_data$PT_LineageFemale)

female_cell_group_df <- female_branch_meta_data

## what's the range of values for each pt?

range(female_cell_group_df$pt)
range(male_cell_group_df$pt)
## make bin widths
# make a new col for annotation
female_cell_group_df$pt_bin <- NA
for(i in seq(4,68,4)){
  female_cell_group_df$pt_bin[which(female_cell_group_df$pt < i & female_cell_group_df$pt >= (i-4))] <- i
}

male_cell_group_df$pt_bin <- NA
for(i in seq(4,68,4)){
  male_cell_group_df$pt_bin[which(male_cell_group_df$pt < i & male_cell_group_df$pt >= (i-4))] <- i
}
# then remove old pt values
male_cell_group_df <- male_cell_group_df[ ,-2]
female_cell_group_df <- female_cell_group_df[ ,-2]
## The original object contains all cells, we just want wild-type so let's subset out gene_module_df and cell_group_df accordingly

## male
## subset our cell group df to keep only these cells
male_cell_group_df <- male_cell_group_df[which(male_cell_group_df$cell_id %in% male_cells),]
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
male_cell_group_df <- data.frame(cell=as.character(factor(male_cell_group_df$cell_id)), cell_group=factor(male_cell_group_df$pt_bin))  
## aggregate expression
male_agg_mat <- aggregate_gene_expression(male.monocle.object, gene_module_df_sex, male_cell_group_df, exclude.na = FALSE)

## female
## subset out only male and pre determination cells
## subset our cell group df to keep only these cells
female_cell_group_df <- female_cell_group_df[which(female_cell_group_df$cell_id %in% female_cells),]
## make a new dataframe for cell groups - it is crucial to refactor otherwise aggregate_gene_expression thinks it's out of bounds  
female_cell_group_df <- data.frame(cell=as.character(factor(female_cell_group_df$cell_id)), cell_group=factor(female_cell_group_df$pt_bin))  
## aggregate expression
female_agg_mat <- aggregate_gene_expression(female.monocle.object, gene_module_df_sex, female_cell_group_df, exclude.na = FALSE)
## use these clusters to reorder the modules
male_agg_mat <- male_agg_mat[match(levels(gene_module_df_sex$module), row.names(male_agg_mat)), ]
female_agg_mat <- female_agg_mat[match(levels(gene_module_df_sex$module), row.names(female_agg_mat)), ]

pheatmap::pheatmap(male_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

pheatmap::pheatmap(female_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE)

expression of modules in mutant cells (side panels)

male

## make monocle object with mutants
## extract data
mutant_cells_male <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$genotype_combined == "Mutant" & tenx.mutant.integrated.sex@meta.data$sex == "male"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = mutant_cells_male)

## make new counts and pheno:
## the reason we use the integrated and then subsetted is because these cells have been normalised whereas the cells in pb_sex_filtered have not been normalised (well they have but with doublets in them)
data <- as(as.matrix(GetAssayData(seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(seurat.object@meta.data)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object.mutants.male <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)

## preprocess
monocle.object.mutants.male = preprocess_cds(monocle.object.mutants.male, num_dim = 50, norm_method = "none")
### if using integrated data:
# norm_method = "none", alignment_group = "~ experiment"

## make a cell group dataframe for aggregating expression values:

mutant_cell_group_df <- data.frame(cell = row.names(monocle.object.mutants.male@colData), cell_group = monocle.object.mutants.male@colData$identity_updated)

## aggregate expression
mutant_male_agg_mat <- aggregate_gene_expression(monocle.object.mutants.male, gene_module_df_sex, mutant_cell_group_df)

plot

mutant_male_agg_mat <- mutant_male_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_male_agg_mat)), ]

pheatmap::pheatmap(mutant_male_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = TRUE) + theme(legend.position = "bottom")
mutant_male_agg_mat <- mutant_male_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_male_agg_mat)), ]

pheatmap::pheatmap(mutant_male_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = TRUE) + theme(legend.position = "bottom")

female

## make monocle object with mutants
## extract data
mutant_cells_female <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$genotype_combined == "Mutant" & tenx.mutant.integrated.sex@meta.data$sex == "female"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = mutant_cells_female)

## make new counts and pheno:
## the reason we use the integrated and then subsetted is because these cells have been normalised whereas the cells in pb_sex_filtered have not been normalised (well they have but with doublets in them)
data <- as(as.matrix(GetAssayData(seurat.object, assay = "RNA", slot = "data")), 'sparseMatrix')
pd <- data.frame(seurat.object@meta.data)
fData <- data.frame(gene_short_name = row.names(data), row.names = row.names(data))

## Construct monocle cds
monocle.object.mutants.female <- new_cell_data_set(expression_data = data, cell_metadata = pd, gene_metadata = fData)

## preprocess
monocle.object.mutants.female = preprocess_cds(monocle.object.mutants.female, num_dim = 50, norm_method = "none")
### if using integrated data:
# norm_method = "none", alignment_group = "~ experiment"

## make a cell group dataframe for aggregating expression values:
mutant_cell_group_df <- data.frame(cell = row.names(monocle.object.mutants.female@colData), cell_group = monocle.object.mutants.female@colData$identity_updated)

## aggregate expression
mutant_female_agg_mat <- aggregate_gene_expression(monocle.object.mutants.female, gene_module_df_sex, mutant_cell_group_df)

plot

mutant_female_agg_mat <- mutant_female_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_female_agg_mat)), ]

pheatmap::pheatmap(mutant_female_agg_mat, 
                   scale="column",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = FALSE) + theme(legend.position = "bottom")
mutant_female_agg_mat <- mutant_female_agg_mat[match(levels(gene_module_df_sex$module), row.names(mutant_female_agg_mat)), ]

pheatmap::pheatmap(mutant_female_agg_mat, 
                   scale="row",
                   #clustering_method="ward.D2",
                   cluster_rows = FALSE,
                   cluster_cols = TRUE) + theme(legend.position = "bottom")

for particular genes (lower panel)

## landmark genes (genes of interest)
# AP2G - PBANKA-1437500
# AP2 - PBANKA-0909600 - from poran paper
# AP2G-2 - PBANKA-1034300 
list_of_mutant_genes <- c("PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")

list_of_genes_of_interest <- c("PBANKA-1437500", "PBANKA-0909600","PBANKA-1034300", "PBANKA-0828000", "PBANKA-1302700", "PBANKA-1447900", "PBANKA-0102400", "PBANKA-0716500", "PBANKA-1435200", "PBANKA-1418100", "PBANKA-1144800", "PBANKA-0902300", "PBANKA-0413400", "PBANKA-1454800")
##make df for genes of interest
genes_of_interest <- data.frame(gene = list_of_genes_of_interest, group = c(1:length(list_of_genes_of_interest)))

## aggregate expression
## make plotting df
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest, cell_group_df)

row.names(agg_mat_genes_of_interest) <- genes_of_interest$gene

#row.names(agg_mat_genes_of_interest) <- factor(row.names(agg_mat_genes_of_interest), levels = row.names(agg_mat_genes_of_interest)[module_dendro$order])
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[,match(rownames(cluster_anno), colnames(agg_mat_genes_of_interest))]

pheatmap::pheatmap(agg_mat_genes_of_interest, 
                   scale="row",
                   cluster_cols = FALSE,
                   cluster_rows = FALSE,
                   clustering_method="ward.D2", 
                   annotation_col = cluster_anno, 
                   annotation_colors = annotation_colours)

complex heat map

## aggregate gene expression
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest, df_all_cells)

agg_mat_genes_of_interest <- as.matrix(agg_mat_genes_of_interest)

## make heatmap
modules_heatmap <- Heatmap(agg_mat_genes_of_interest,
        column_order = NULL,
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")
## order cols in the matrix
agg_mat_genes_of_interest <- agg_mat_genes_of_interest[ ,match(rownames(df_anno), colnames(agg_mat_genes_of_interest))]

## make heatmap
modules_heatmap <- Heatmap(agg_mat_genes_of_interest,
        column_order = NULL,
        cluster_columns = TRUE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

Using Seurat to visualise cells

# find markers for every cluster compared to all remaining cells, report only the positive ones
tenx.mutant.integrated.sex.markers <- FindAllMarkers(tenx.mutant.integrated.sex, only.pos = TRUE, min.pct = 0.25, logfc.threshold = 0.25)
tenx.mutant.integrated.sex.markers %>% group_by(cluster) %>% top_n(n = 2, wt = avg_logFC)
top10 <- tenx.mutant.integrated.sex.markers %>% group_by(cluster) %>% top_n(n = 10, wt = avg_logFC)
DoHeatmap(tenx.mutant.integrated.sex, features = top10$gene) + NoLegend()

But we also have the old pt values that we can use in the seurat object ie FeaturePlot(tenx.mutant.integrated.sex, reduction = “pca”, pt.size = 0.01, features = “old_pt_values”)

So let’s plot a heatmap where we plot: (x) all cells vs. (y) genes arranged by module that they belong to.

add an old pt annotation to the top

prepare data:

## extracts only 10x cells 
wt_cells <- rownames(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"),])

## make a new Seurat of this
seurat.object <-SubsetData(tenx.mutant.integrated.sex, cells = wt_cells)
DoHeatmap(seurat.object, features = top10$gene) + NoLegend()
## aggregate gene expression
agg_mat_genes_of_interest <- aggregate_gene_expression(monocle.object, genes_of_interest, df_all_cells)

agg_mat_genes_of_interest <- as.matrix(agg_mat_genes_of_interest)

## make heatmap
modules_heatmap <- Heatmap(agg_mat_genes_of_interest,
        column_order = NULL,
        cluster_columns = FALSE,
        cluster_rows = FALSE,
        show_column_dend = FALSE,
        column_labels = rep("", ncol(agg_mat_all_cells_matrix)),
        #row_order = module_dendro$order,
        clustering_method_columns = "ward.D2",
        bottom_annotation = heatmap_annotation,
        col = colorRampPalette(rev(brewer.pal(n = 7, name =
  "RdYlBu")))(100), 
        heatmap_legend_param = list(direction = "horizontal"))

## print
draw(modules_heatmap, merge_legend = TRUE, heatmap_legend_side = "bottom", 
    annotation_legend_side = "bottom")

Expression of CCP2 and MG1 by each genotype and each sex

# ccp2 - "PBANKA-1319500" - female 820
# MG1 - "PBANKA-0416100" - male 820

## make a custom dataframe:
marker_820_df <- as.data.frame(t(as.data.frame(tenx.mutant.integrated.sex@assays$RNA@data[c("PBANKA-1319500", "PBANKA-0416100"), ], stringsAsFactors=F)))
marker_820_df$cell_id <- row.names(marker_820_df)
sex_id <- data.frame(sex_at = tenx.mutant.integrated.sex@meta.data$at_sex, genotype = tenx.mutant.integrated.sex@meta.data$identity_updated ,cell_id = row.names(tenx.mutant.integrated.sex@meta.data))
marker_820_df <- merge(marker_820_df, sex_id, by = "cell_id")

ggplot(marker_820_df, aes(fill=sex_at, y=`PBANKA-1319500`, x=genotype)) + 
    geom_violin() +
  geom_jitter(shape=16, position=position_jitter(0.2)) +
  theme_classic() +
  theme(axis.text.x = element_text(angle = 90))
#tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$sex == "pre-det" | tenx.mutant.integrated.sex@meta.data$sex == "female"), ]


VlnPlot(tenx.mutant.integrated.sex, group.by = "identity_updated", split.by = "at_sex", features = c("PBANKA-1319500"), split.plot = TRUE)

VlnPlot(tenx.mutant.integrated.sex, group.by = "identity_updated", split.by = "at_sex", features = c("PBANKA-0416100"), split.plot = TRUE)

Differential expression

Re-cluster the data so we have very course grain clusters

## find new clusters
tenx.mutant.integrated.sex <- FindClusters(tenx.mutant.integrated.sex, resolution = 1, random.seed = 42, algorithm = 2)

## plot the graph
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.1") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom") +
  guides(colour=guide_legend(nrow=3,byrow=TRUE, override.aes = list(size=4)))
VlnPlot(tenx.mutant.integrated.sex, features = c("PT_Female_UMAP", "PT_Male_UMAP"))

Show representation of genotypes per cluster

prep for dotplot

## make a dataframe that is the meta data
df_meta_data <- as.data.frame(tenx.mutant.integrated.sex@meta.data)

## define order for plotting 
my_levels_sex <- c("2", "3", "9", "6", "11", "5", "0", "10", "13", "14", "12", "8", "15", "1", "4", "7")

## redefine order of clusters:
df_meta_data$seurat_clusters <- factor(x = df_meta_data$seurat_clusters, levels = my_levels_sex)

## make a new df of CLUSTER and IDENTITY
dot_plot_df <- as.data.frame.matrix(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined))
dot_plot_df$cluster <- rownames(dot_plot_df)

## calculate percentage of cells for each genotype
dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$seurat_clusters, df_meta_data$identity_combined), margin = 2)) * 100)

## make a column for cluster names
dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)

## melt dataframe for plotting
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"

## melt the raw number too
dot_plot_df_melted <- melt(dot_plot_df, variable.name = "cluster")
colnames(dot_plot_df_melted)[2] <- "identity"
colnames(dot_plot_df_melted)[3] <- "raw_number"

## merge together
identical(dot_plot_df_melted$cluster, dot_plot_df_pc_melted$cluster)
dot_plot_merged <- cbind(dot_plot_df_melted, dot_plot_df_pc_melted)
dot_plot_merged <- dot_plot_merged[,c(1,2,3,6)]

## redefine order of clusters
dot_plot_merged$cluster <- factor(x = dot_plot_merged$cluster, levels = my_levels_sex)

## where values are zero, add NA
## find wells where it's zero
zero_values <- dot_plot_merged$value == 0
dot_plot_merged$value[zero_values] <- NA

## also do for raw number
zero_values <- dot_plot_merged$raw_number == 0
dot_plot_merged$raw_number[zero_values] <- NA

## reorder x axis:
my_levels_genotype <- c("GCSKO-oom", "GCSKO-29", "GCSKO-2", "GCSKO-19", "GCSKO-3", "GCSKO-21", "GCSKO-13", "GCSKO-28", "GCSKO-10_820", "GCSKO-17", "GCSKO-20", "WT", "WT_10X")

dot_plot_merged$identity <- factor(x = dot_plot_merged$identity, levels = my_levels_genotype)

plot

## plot
dot_plot_identity <- ggplot(dot_plot_merged, aes(y = factor(cluster), x = factor(identity))) +
      ## make into a dot plot
      geom_point(aes(colour=value, size=raw_number)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 0, max(dot_plot_df_pc_melted$value)), na.value="white") +
      #change the colours
      scale_colour_viridis(option = "inferno", guide = "colourbar", na.value="white") +
      theme_classic() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank(), text=element_text(size=16,  family="Arial")) +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, angle=45, hjust=1, vjust=1), axis.text.y=element_text(size=12,), legend.position = "bottom", plot.margin = unit(c(1,3,1,3), "lines")) +
    ## annotate males
    geom_hline(aes(yintercept = 2.5)) +
    ## annotate females
    geom_hline(aes(yintercept = 7.5)) +
    ## annotate pheno 1
    geom_vline(aes(xintercept = 4.5)) +
    ## annotate pheno 2
    geom_vline(aes(xintercept = 5.5)) +    
    ## annotate pheno 3
    geom_vline(aes(xintercept = 7.5)) +
    ## annotate pheno 4
    geom_vline(aes(xintercept = 11.5))

## print
print(dot_plot_identity)

cut off and plot

pre_branch_cells <- c(2,3)
inmature_male_cells <- c()
inmature_female_cells <-
mature_male_cells <- 
mature_female_cells <- 

## plot the graph
DimPlot(tenx.mutant.integrated.sex, reduction = "umapoptimised_post_repca", label = TRUE, repel = TRUE, label.size = 5, pt.size = 0.5, group.by = "integrated_snn_res.1") +
  coord_fixed() +
  theme_void() +
  theme(legend.position = "bottom")
wt_cells <- row.names(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" | tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"), ])

male_inmature_cells <- row.names(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" | tenx.mutant.integrated.sex@meta.data$identity_combined == "WT_10X"), ])



early_wt_cells <- row.names(tenx.mutant.integrated.sex@meta.data[which(tenx.mutant.integrated.sex@meta.data$identity_combined == "WT" && tenx.mutant.integrated.sex@meta.data$PT_LineageFemale < 46), ])

FindMarkers(tenx.mutant.integrated.sex, cells.1 = , cells.2 = )

Save and Export

This saves everything in the global environment for easy recall later

save.image(file = "GCSKO_Sex_Branch_Analysis.RData")
#load(file = "GCSKO_Sex_Branch_Analysis.RData")
#gene_module_df_sex
write.csv(gene_module_df_sex, file = "gene_module_df_sex.csv")
#save(pb_30k_sex_filtered, pb_sex_filtered, file = "Part_2_input.Rdata")

Appendix

Functions Info

Seurat:::DoHeatmap
monocle:::plot_pseudotime_heatmap
getAnywhere(aggregate_gene_expression)

so essentially it first takes the counts matrix and subsets it by your gene groups, then it sums the values - if you specify scale then it will calcualte the z score of the transformed dataframe

A. Diffusion Map

construct map

## construct diffusion map
## http://www.bioconductor.org/packages/devel/bioc/vignettes/slingshot/inst/doc/vignette.html
## input is a transformed expression matrix (genes as cols and cells as rows)
dm <- DiffusionMap(t(as.data.frame(tenx.mutant.integrated.sex@assays$integrated@data)))

## extract meta data for plotting
df_meta_data <- (as.data.frame(tenx.mutant.integrated.sex@meta.data))

## make combined dataframe
rd2 <- as.data.frame(cbind(DC1 = dm$DC1, DC2 = dm$DC2, identity = as.factor(as.character(tenx.mutant.integrated.sex@meta.data$post_integration_clusters))))

## plot
ggplot(rd2, aes(x = DC1, y = DC2, colour = as.character(identity))) + geom_point(size = 1) + 
  theme(axis.ticks.y = element_blank()) + 
  theme_classic()
LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSguLi9HQ1NLT19sb2dvLmpwZyl7d2lkdGg9MzAwcHh9ICAKICBQc2V1ZG90aW1lIFNleHVhbCBCcmFuY2gKYXV0aG9yOiAiW0FuZHJldyBSdXNzZWxsXShodHRwczovL2FqY3J1c3NlbGwud2l4c2l0ZS5jb20vbXlzaXRlL2Fib3V0KSIKaW5zdGl0dXRlOiBXZWxsY29tZSBTYW5nZXIgSW5zdGl0dXRlCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgICN0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoqKioKIyAxLiBJbnRyb2R1Y3Rpb24gYW5kIEFpbXMgey50YWJzZXR9CgpXZSBoYXZlIG1lcmdlZCB0aGUgdHdvIGRhdGFzZXRzIHRvZ2V0aGVyIGluIEdDU0tPX21lcmdlLlJtZC4gV2UgYWxzbyBzdWJzZXR0ZWQgb3V0IHRoZSBwcmUtc2V4dWFsLWJyYW5jaCBhbmQgdGhlIHNleHVhbCBjZWxscyAobWFsZSBhbmQgZmVtYWxlKSBhbmQgc3RvcmVkIHRoZW0gaW4gYSBTZXVyYXQgb2JqZWN0IGNhbGxlZCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC4gSGVyZSwgd2Ugd2lsbCBwZXJmb3JtIHBzZXVkb3RpbWUgYW5hbHlzaXMgb24gdGhlIGRhdGFzZXQgYW5kIGJ1aWxkIG1vZHVsZXMgb2YgZ2VuZXMgdGhhdCBzaG93IHNpbWlsYXIgZXhwcmVzc2lvbiBhY3Jvc3MgdGhpcyBwc2V1ZG90aW1lLgoKIyAyLiBSZWFkIGluIHRoZSBkYXRhICB7LnRhYnNldH0KCiMjIExvYWQvSW5zdGFsbCB0aGUgUmVxdWlyZWQgUGFja2FnZXMKCmBgYHtyIGxvYWQgcGFja2FnZXMsIGVjaG8gPSBGQUxTRX0KIyMgQ1JBTiBwYWNrYWdlcwoKIyMgUGF0Y2h3b3JrIGlzIG5lZWRlZCB0byBzdGljaCBwbG90cyB0b2dldGhlciB1c2luZyAnKycKaWYocmVxdWlyZSgicGF0Y2h3b3JrIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJwYXRjaHdvcmsgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgcGF0Y2h3b3JrIikKICAgIGluc3RhbGwucGFja2FnZXMoInBhdGNod29yayIpCiAgICBpZihyZXF1aXJlKHBhdGNod29yaykpewogICAgICAgIHByaW50KCJwYXRjaHdvcmsgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBwYXRjaHdvcmsiKQogICAgfQp9CgojIyB2aXJpZGlzIGFsbG93cyBkaWZmZXJlbnQgY29sb3VycyB0byBiZSBhZGRlZCB0byBwbG90cwppZihyZXF1aXJlKCJ2aXJpZGlzIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJ2aXJpZGlzIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIHZpcmlkaXMiKQogICAgaW5zdGFsbC5wYWNrYWdlcygidmlyaWRpcyIpCiAgICBpZihyZXF1aXJlKHZpcmlkaXMpKXsKICAgICAgICBwcmludCgidmlyaWRpcyBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIHZpcmlkaXMiKQogICAgfQp9CgojIyBTZXVyYXQgaXMgbmVlZGVkIGZvciBtb3N0IG9mIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoIlNldXJhdCIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgiU2V1cmF0IGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIFNldXJhdCIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJTZXVyYXQiKQogICAgaWYocmVxdWlyZShTZXVyYXQpKXsKICAgICAgICBwcmludCgiU2V1cmF0IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgU2V1cmF0IikKICAgIH0KfQoKIyMgY293cGxvdCBpcyBuZWVkZWQgZm9yIHBsb3RzIGluIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoImNvd3Bsb3QiKSl7CiAgICBwcmludCgiY293cGxvdCBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBjb3dwbG90IikKICAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQogICAgaWYocmVxdWlyZShjb3dwbG90KSl7CiAgICAgICAgcHJpbnQoImNvd3Bsb3QgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBjb3dwbG90IikKICAgIH0KfQoKIyMgZ3JpZEV4dHJhIGlzIG5lZWRlZCBmb3IgZ3JpZCBncmFwaGljcyB0byBwbG90IG11bHRpcGxlIHBsb3RzIGluIHRoZSBzYW1lIHZpZXcKaWYocmVxdWlyZSgiZ3JpZEV4dHJhIikpewogICAgcHJpbnQoImdyaWRFeHRyYSBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBncmlkRXh0cmEiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZEV4dHJhIikKICAgIGlmKHJlcXVpcmUoZ3JpZEV4dHJhKSl7CiAgICAgICAgcHJpbnQoImdyaWRFeHRyYSBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWRFeHRyYSIpCiAgICB9Cn0KCiMjIGdyaWQgaXMgbmVlZGVkIGZvciBncmlkLmFycmFuZ2UgZnVuY3Rpb24gdG8gY2hhbmdlIHNpemUgb2YgdGl0bGUKaWYocmVxdWlyZSgiZ3JpZCIpKXsKICAgIHByaW50KCJncmlkIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGdyaWQiKQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ3JpZCIpCiAgICBpZihyZXF1aXJlKGdyaWQpKXsKICAgICAgICBwcmludCgiZ3JpZCBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIGdyaWQiKQogICAgfQp9CgojI2ZvciBkb2luZyBidWxrIGNvcnJlbGF0aW9uIGNhbGN1bGF0aW9ucwppZihyZXF1aXJlKCJIbWlzYyIpKXsKICAgIHByaW50KCJIbWlzYyBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBIbWlzYyIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJIbWlzYyIpCiAgICBpZihyZXF1aXJlKEhtaXNjKSl7CiAgICAgICAgcHJpbnQoIkhtaXNjIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgSG1pc2MiKQogICAgfQp9CgojIyByZXNoYXBlMiB0byBtZWx0IGRhdGFmcmFtZXMgZm9yIHBsb3R0aW5nOgppZihyZXF1aXJlKCJyZXNoYXBlMiIpKXsKICAgIHByaW50KCJyZXNoYXBlMiBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCByZXNoYXBlMiIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJyZXNoYXBlMiIpCiAgICBpZihyZXF1aXJlKHJlc2hhcGUyKSl7CiAgICAgICAgcHJpbnQoInJlc2hhcGUyIGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgcmVzaGFwZTIiKQogICAgfQp9CgojIyB0byB3b3JrIHdpdGggZGF0YSBmcmFtZXM6CmlmKHJlcXVpcmUoImRwbHlyIikpewogICAgcHJpbnQoImRwbHlyIGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGRwbHlyIikKICAgIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikKICAgIGlmKHJlcXVpcmUoZHBseXIpKXsKICAgICAgICBwcmludCgiZHBseXIgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBkcGx5ciIpCiAgICB9Cn0KCiMjIG5vbi1DUkFOIHBhY2thZ2VzCgojIyBtb25vY2xlMyB0byBjYWxjdWxhdGUgcHNldWRvdGltZToKaWYocmVxdWlyZSgibW9ub2NsZTMiKSl7CiAgICBwcmludCgibW9ub2NsZTMgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgiUGxlYXNlIGluc3RhbGwgbW9ub2NsZTMgKGh0dHBzOi8vY29sZS10cmFwbmVsbC1sYWIuZ2l0aHViLmlvL21vbm9jbGUzL2RvY3MvaW5zdGFsbGF0aW9uLykiKQp9CgojIyBkZXN0aW55IGlzIHVzZWQgZm9yIGRpZmZ1c2lvbiBwbG90cyAoRGlmZnVzaW9uTWFwIGZ1bmN0aW9uKQppZihyZXF1aXJlKCJkZXN0aW55IikpewogICAgcHJpbnQoImRlc3RpbnkgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIGRlc3RpbnkiKQogIGlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJCaW9jTWFuYWdlciIpCiAgQmlvY01hbmFnZXI6Omluc3RhbGwoImRlc3RpbnkiKQogIGlmKHJlcXVpcmUoZGVzdGlueSkpewogICAgICAgIHByaW50KCJkZXN0aW55IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgZGVzdGlueSIpCiAgICB9Cn0KCiNzZXQgdGhlIHNlZWQgZm9yIGJvdGggdGhlIG1peHR1cmUgbW9kZWxzIGFuZCBhbHNvIGZvciB0aGUgc2FtcGxlIGZ1bmN0aW9uIGxhdGVyIG9uOgpzZXQuc2VlZCgtOTI0OTcpCmBgYAoKIyMgbG9hZCBkYXRhCgpgYGB7cn0KIyMgbG9hZCBzZXggb25seSBicmFuY2ggY2VsbHMgc2F2ZWQgZnJvbSBHQ1NLT19TZXhfQnJhbmNoX0FuYWx5c2lzLlJtZAojIyBSZXN0b3JlIHRoZSBvYmplY3RzCiMjIGxvYWQgc2V4IGJyYW5jaCBkYXRhc2V0CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIHJlYWRSRFMoIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4LlJEUyIpCiMjIGxvYWQgZnVsbCBkYXRhc2V0CiN0ZW54Lm11dGFudC5pbnRlZ3JhdGVkIDwtIHJlYWRSRFMoIi4uL2RhdGFfdG9fZXhwb3J0L3RlbngubXV0YW50LmludGVncmF0ZWQuUkRTIikKYGBgCgpgYGB7cn0KIyMgYWRkIG9sZCBwdCB2YWx1ZXMKIyMgdGhlc2UgdmFsdWVzIGFyZSBjYWxjdWxhdGVkIGluIGh0ZSBHQ1NLT19wc2V1ZG90aW1lX2FsbGNlbGxzLlJtZCBzY3JpcHQgYW5kIHNvIHdlcmUgYWRkZWQgYWZ0ZXIgdGhlIG9iamVjdCB3YXMgc3BsaXQgaW50byBzZXggb25seS4KdGVueC5hbGwgPC0gcmVhZFJEUygiLi4vZGF0YV90b19leHBvcnQvdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5SRFMiKQp0ZW54LmFsbC5tZXRhIDwtIGFzLmRhdGEuZnJhbWUodGVueC5hbGxAbWV0YS5kYXRhKQp0ZW54LmFsbC5tZXRhIDwtIHRlbnguYWxsLm1ldGFbd2hpY2gocm93bmFtZXModGVueC5hbGwubWV0YSkgJWluJSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEpKSxdCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEFkZE1ldGFEYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCB0ZW54LmFsbC5tZXRhJG9sZF9wdF92YWx1ZXMsIGNvbC5uYW1lID0gIm9sZF9wdF92YWx1ZXMiKQojIyB0aGVuIHJlbW92ZSB0aGVzZSBvYmplY3RzIHNvIHRoZXkgZG9uJ3QgdXNlIHVwIG1lbW9yeQpybSh0ZW54LmFsbCwgdGVueC5hbGwubWV0YSkKYGBgCgojIDMuIERpbWVuc2lvbmFsdHkgUmVkdWN0aW9uIHsudGFic2V0fQoKV2Ugd2lsbCBub3cgcmUtY2FsY3VsYXRlIHRoZSBVTUFQLCBQQ0EgYW5kIGRpZmZ1c2lvbiBtYXAgdG8gdmlzdWFsaXNlIHRoZSBkYXRhIHNpbmNlIHRoZSBvbGQgdmlzdWFsaXNhdGlvbiB1c2VkIHRoZSB2YXJpYXRpb24gaW4gdGhlIHdob2xlIGRhdGFzZXQgYW5kIHNvIHNvbWUgb2YgdGhlIHZhcmlhdGlvbiBpbiB0aGlzIHNldCBvZiBjZWxscyB3YXMgb2JzY3VyZWQuCgpyZWY6IGh0dHBzOi8vZ2l0aHViLmNvbS9zYXRpamFsYWIvc2V1cmF0L2lzc3Vlcy8xODgzCgojIyBBLiBSZWNhbGN1bGF0ZSBQQ0EKClRoZSBQQ0EgaXMgdXNlZCBhcyB0aGUgYmFzaXMgb2Ygb3RoZXIgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9ucyBzbyB3ZSB3aWxsIG5vdyByZWNhbGN1bGF0ZSB0aGlzIHRvIGdldCB0byBvdXIgZmluYWwgVU1BUC4KCkZpcnN0LCBydW4gUENBIGFnYWluCmBgYHtyfQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBSdW5QQ0EodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQpgYGAKClRoZW4gaW5zcGVjdCB0aGUgUENzCmBgYHtyfQpFbGJvd1Bsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIG5kaW1zID0gMzAsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCkhhdmUgYSBxdWljayBsb29rIGF0IHRoZSBvdXRwdXQKYGBge3J9CkZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAicGNhIiwgcHQuc2l6ZSA9IDAuMDEsIGZlYXR1cmVzID0gIm9sZF9wdF92YWx1ZXMiKQpgYGAKCiMjIEIuIFVNQVAKCmNhbGN1bGF0ZSBVTUFQCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KIyMgcnVuIFVNQVAKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gUnVuVU1BUCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjE1LCBuLm5laWdoYm9ycyA9IDIwLCBzZWVkLnVzZSA9IDEyMzQsIG1pbi5kaXN0ID0gMC41LCByZXB1bHNpb24uc3RyZW5ndGggPSAwLjA1LCByZWR1Y3Rpb24ubmFtZSA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiKQoKIyMgcGxvdApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBzcGxpdC5ieSA9ICJnZW5vdHlwZV9jb21iaW5lZCIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKY2hlY2sgbWFya2VycyB0byBvcmllbnRhdGUKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxMH0KcGxvdHMgPC0gRmVhdHVyZVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGZlYXR1cmVzID0gYygiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiKSwgYmxlbmQgPSBUUlVFLCBjb21iaW5lID0gRkFMU0UsIGNvb3JkLmZpeGVkID0gVFJVRSwgcmVkdWN0aW9uID0gInVtYXBvcHRpbWlzZWRfcG9zdF9yZXBjYSIpCgpwbG90c1tbM11dICsgTm9MZWdlbmQoKSAgIyBHZXQganVzdCB0aGUgY28tZXhwcmVzc2lvbiBwbG90LCBidWlsdC1pbiBsZWdlbmQgaXMgbWVhbmluZ2xlc3MgZm9yIHRoaXMgcGxvdApwbG90c1tbNF1dICMgR2V0IGp1c3QgdGhlIGtleQpDb21iaW5lUGxvdHMocGxvdHNbMzo0XSwgbGVnZW5kID0gJ25vbmUnLCBuY29sID0yLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoMiwgMSksIHJlbF9oZWlnaHRzID0gYyg0LDEpKSAjIFN0aXRjaCB0aGUgY28tZXhwcmVzc2lvbiBhbmQga2V5IHBsb3RzIHRvZ2V0aGVyCmBgYAoKIyA0LiBDbHVzdGVyaW5nIHsudGFic2V0fQoKIyMjIEdlbmVyYXRlIE5ldyBDbHVzdGVycwoKV2UgbXVzdCBub3cgcmVjYWxjdWxhdGUgdGhlIGNsdXN0ZXJzIHRvIGdhaW4gYSBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgaGV0ZXJvZ2VuZWl0eSBvZiB0aGUgc3Vic2V0LiBTaW5jZSB1c2luZyB0aGUgcHJldmlvdXMgY2x1c3RlcnMsIHRoZSBhc2V4dWFsIGNlbGxzIG9ic2N1cmVkIHNvbWUgb2YgdGhlIHZhcmlhdGlvbi4gCgpgYGB7cn0KIyMgY29weSBvbGQgY2x1c3RlcnMKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMsIGNvbC5uYW1lID0gInByZV9zZXhfY2x1c3RlcnMiKQpgYGAKCmBgYHtyfQojIyBnZW5lcmF0ZSBuZXcgY2x1c3RlcnMgYXQgdmFyaW91cyByZXNvbHV0aW9ucwp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBGaW5kTmVpZ2hib3JzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBkaW1zID0gMToxNSkKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gRmluZENsdXN0ZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZXNvbHV0aW9uID0gYygyLDMsNCw1LDYpLCByYW5kb20uc2VlZCA9IDQyLCBhbGdvcml0aG0gPSAyKQpgYGAKCiMjIyBWaXN1YWxpc2UKCiMjIyMgQ2hvb3NlIENsdXN0ZXIgUmVzb2x1dGlvbgoKVmlldyB0aGUgY2x1c3RlcnMgYXQgZGlmZmVyZW50IHJlc29sdXRpb25zIHRvIGNob3NlIHRoZSBhcHByb3ByYWl0ZSByZXNvbHV0aW9uCmBgYHtyfQojIyBwbG90CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4yIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy4zIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy40IikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy41IikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKCkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHJlZHVjdGlvbiA9ICJ1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2EiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgbGFiZWwuc2l6ZSA9IDUsIHB0LnNpemUgPSAwLjUsIGdyb3VwLmJ5ID0gImludGVncmF0ZWRfc25uX3Jlcy42IikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgpHbyB3aXRoIDQgY2x1c3RlcnMKYGBge3J9CnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVzb2x1dGlvbiA9IDQsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgpEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41KSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCiMjIyMgT3JpZ2luYWwgVU1BUAoKWW91IGNhbiBhbHNvIHVzZSB0aGUgb3JpZ2luYWwgVU1BUCBwcm9qZWN0aW9uCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41KSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCiMjIyMgUmVwcmVzZW50YXRpb24KCmxvb2sgYXQgY2x1c3RlciByZXByZXNlbnRhdGlvbgpgYGB7ciwgZWNobyA9IEZBTFNFfQojIyBmb3IgbG9vcCB3aGljaCB0YWtlcyBlYWNoIGNsdXN0ZXIgYW5kIG1ha2VzIGEgbGlzdCBvZiBjZWxscyBhbmQgdGhlbiBwbG90cyBhIGhpZ2hsaWdodGVkIHBsb3QgYW5kIGFkZHMgaXQgdG8gYSBsaXN0CgojIyBtYWtlIGEgZGYgb2YgdGhlIG51bWJlciBvZiAKbl9wZXJfY2x1c3RlciA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKQpyb3duYW1lcyhuX3Blcl9jbHVzdGVyKSA8LSBuX3Blcl9jbHVzdGVyJFZhcjEKbl9wZXJfY2x1c3RlciA8LSBuX3Blcl9jbHVzdGVyWywyXQoKIyMgbWFrZSBhIGJsYW5rIGxpc3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSkKCiMjIGZvciBsb29wCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKXsKICAjIyBtYWtlIGEgbGlzdCBvZiBjZWxscwogIGxpc3Rfb2ZfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpW2ldKSwgXSkKICB1bWFwX3Bsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBsaXN0X29mX2NlbGxzLCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIikgKyAKICBjb29yZF9maXhlZCgpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMDAwMDAwIiwgIiNmNTRlMWUiKSkgKyAKICB0aGVtZV92b2lkKCkgKyAKICBsYWJzKHRpdGxlID0gcGFzdGUoImNsdXN0ZXIiLCBsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycylbaV0sICJcbiIsICIobiA9ICIsIG5fcGVyX2NsdXN0ZXJbaV0sIikiKSkgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSwgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQogICMjIGFkZCB0byB0aGUgbGlzdAogIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbaV1dIDwtIHVtYXBfcGxvdAp9CmBgYAoKcGxvdApgYGB7cn0KIyMgdGhpcyBmdW5jdGlvbiB3cml0ZXMgdGhlIG5leHQgYml0IG9mIGNvZGUgZm9yIHlvdQpwbG90eSA8LSBjKCkKZm9yKGkgaW4gc2VxX2Fsb25nKGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKSkpewogIHBsb3R5IDwtIHBhc3RlMChwbG90eSwgImxpc3RfVU1BUHNfYnlfY2x1c3RlcltbIiwgaSwgIl1dIiwgIiArICIpCn0KYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDE1LCBmaWcud2lkdGggPSAyMH0KIyMgcGxvdApsaWJyYXJ5KGdyaWRFeHRyYSkKZ3JpZC5hcnJhbmdlKGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzNdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s1XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzZdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbN11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s4XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzldXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTBdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTFdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTJdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTNdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTRdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTVdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTZdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTddXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMThdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMTldXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjBdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjFdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjJdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjNdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjRdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjVdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjZdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjddXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjhdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMjldXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzBdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbMzFdXSwgbmNvbCA9IDUpCmBgYAoKCmBgYHtyfQojIyBmb3IgbG9vcCB3aGljaCB0YWtlcyBlYWNoIGNsdXN0ZXIgYW5kIG1ha2VzIGEgbGlzdCBvZiBjZWxscyBhbmQgdGhlbiBwbG90cyBhIGhpZ2hsaWdodGVkIHBsb3QgYW5kIGFkZHMgaXQgdG8gYSBsaXN0CgojIyBtYWtlIGEgZGYgb2YgdGhlIG51bWJlciBvZiAKbl9wZXJfY2x1c3RlciA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKQpyb3duYW1lcyhuX3Blcl9jbHVzdGVyKSA8LSBuX3Blcl9jbHVzdGVyJFZhcjEKbl9wZXJfY2x1c3RlciA8LSBuX3Blcl9jbHVzdGVyWywyXQoKIyMgbWFrZSBhIGJsYW5rIGxpc3QKbGlzdF9VTUFQc19ieV9jbHVzdGVyIDwtIHZlY3Rvcihtb2RlID0gImxpc3QiLCBsZW5ndGggPSBsZW5ndGgobGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSkKCiMjIGZvciBsb29wCmZvcihpIGluIHNlcV9hbG9uZyhsZXZlbHModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycykpKXsKICAjIyBtYWtlIGEgbGlzdCBvZiBjZWxscwogIGxpc3Rfb2ZfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgPT0gbGV2ZWxzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMpW2ldKSwgXSkKICB1bWFwX3Bsb3QgPC0gRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgIHJlZHVjdGlvbiA9ICJ1bWFwIiwgbGFiZWwgPSBGQUxTRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4xLCBjZWxscy5oaWdobGlnaHQgPSBsaXN0X29mX2NlbGxzKSArIAogIGNvb3JkX2ZpeGVkKCkgKyAKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMwMDAwMDAiLCAiI2Y1NGUxZSIpKSArIAogIHRoZW1lX3ZvaWQoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiY2x1c3RlciIsIGxldmVscyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzKVtpXSwgIlxuIiwgIihuID0gIiwgbl9wZXJfY2x1c3RlcltpXSwiKSIpKSArIAogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCiAgIyMgYWRkIHRvIHRoZSBsaXN0CiAgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1tpXV0gPC0gdW1hcF9wbG90Cn0KYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDE1LCBmaWcud2lkdGggPSAyMH0KIyMgcGxvdApncmlkLmFycmFuZ2UobGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxXV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzJdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbM11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s0XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzVdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbNl1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1s3XV0gLCBsaXN0X1VNQVBzX2J5X2NsdXN0ZXJbWzhdXSAsIGxpc3RfVU1BUHNfYnlfY2x1c3RlcltbOV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxMl1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxM11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxNl1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxN11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1sxOV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syMl1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syM11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syNF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syNV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syNl1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syN11dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syOF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1syOV1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szMF1dICwgbGlzdF9VTUFQc19ieV9jbHVzdGVyW1szMV1dLCBuY29sID0gNSkKYGBgCgojIyMjIFNob3cgY29ycmVzcG9uZGFuY2Ugd2l0aCBvbGQgY2x1c3RlcnMgKEFsbHV2aXVtIHBsb3QsIFNhbmtleSBkaWFncmFtKQoKYGBge3J9CiMjVGhpcyBpcyB0aGUgc2V0IHVwIGZvciB0aGlzOgojIyB0d28gY2x1c3RlcnMgdGhhdCBkaWZmZXIKdGFibGUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycywgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHByZV9zZXhfY2x1c3RlcnMpCmBgYAoKYGBge3J9CiMjIG1ha2UgYSBkYXRhZnJhbWUgdGhhdCBpcyB0aGUgbWV0YSBkYXRhCmRmX21ldGFfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSkKCmRmX2FsbHV2aWFsIDwtIG1lbHQodGFibGUoZGF0YS5mcmFtZShmdWxsX2NsdXN0ZXJzID0gZGZfbWV0YV9kYXRhJHByZV9zZXhfY2x1c3RlcnMsIHNleF9jbHVzdGVycyA9IGRmX21ldGFfZGF0YSRzZXVyYXRfY2x1c3RlcnMpKSkKCiMjIGxvYWQgcmVxdWlyZWQgcGFja2FnZQpsaWJyYXJ5KGdnYWxsdXZpYWwpCgojIyBwbG90CmdncGxvdChkZl9hbGx1dmlhbCwgYWVzKHkgPSB2YWx1ZSwgYXhpczEgPSBmdWxsX2NsdXN0ZXJzLCBheGlzMiA9IHNleF9jbHVzdGVycykpICsKICBnZW9tX2FsbHV2aXVtKGFlcyhmaWxsID0gc2V4X2NsdXN0ZXJzKSwKICAgICAgICAgICAgICAgIHdpZHRoID0gMCwga25vdC5wb3MgPSAwLCByZXZlcnNlID0gRkFMU0UpICsKICBndWlkZXMoZmlsbCA9IEZBTFNFKSArCiAgZ2VvbV9zdHJhdHVtKHdpZHRoID0gMS84LCByZXZlcnNlID0gRkFMU0UpICsKICBnZW9tX3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgaW5mZXIubGFiZWwgPSBUUlVFLCByZXZlcnNlID0gRkFMU0UpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToyLCBsYWJlbHMgPSBjKCJvcmlnaW5hbCBjbHVzdGVyIiwgIlNleCBDbHVzdGVyIikpICsKICBjb29yZF9mbGlwKCkgKwogIGdndGl0bGUoIkNsdXN0ZXIgSWRlbnRpaXR5IGluIGZ1bGwgZGF0YXNldCB2cy4gc2V4IG9ubHkiKSArCiAgICB0aGVtZV9jbGFzc2ljKCkKYGBgCgojIyMjIFNob3cgcmVwcmVzZW50YXRpb24gb2YgZ2Vub3R5cGVzIHBlciBjbHVzdGVyCgpwcmVwIGZvciBkb3RwbG90CmBgYHtyfQojIyBtYWtlIGEgZGF0YWZyYW1lIHRoYXQgaXMgdGhlIG1ldGEgZGF0YQpkZl9tZXRhX2RhdGEgPC0gYXMuZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEpCgojIyBkZWZpbmUgb3JkZXIgZm9yIHBsb3R0aW5nIApteV9sZXZlbHNfc2V4IDwtIGMoIjAiLCAiOSIsICIyOCIsICIyIiwgIjI5IiwgIjE2IiwgIjIyIiwgIjIzIiwgIjE1IiwgIjIxIiwgIjMwIiwgIjQiLCAiMyIsICIxOCIsICI3IiwgIjgiLCAiNiIsICIyMCIsICIxMiIsICIyNiIsICIxMyIsICI1IiwgIjExIiwgIjI1IiwgIjEiLCAiMTciLCAiMTAiLCAiMjQiLCAiMTQiLCAiMjciLCAiMTkiKQoKIyMgcmVkZWZpbmUgb3JkZXIgb2YgY2x1c3RlcnM6CmRmX21ldGFfZGF0YSRzZXVyYXRfY2x1c3RlcnMgPC0gZmFjdG9yKHggPSBkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzLCBsZXZlbHMgPSBteV9sZXZlbHNfc2V4KQoKIyMgbWFrZSBhIG5ldyBkZiBvZiBDTFVTVEVSIGFuZCBJREVOVElUWQpkb3RfcGxvdF9kZiA8LSBhcy5kYXRhLmZyYW1lLm1hdHJpeCh0YWJsZShkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfY29tYmluZWQpKQpkb3RfcGxvdF9kZiRjbHVzdGVyIDwtIHJvd25hbWVzKGRvdF9wbG90X2RmKQoKIyMgY2FsY3VsYXRlIHBlcmNlbnRhZ2Ugb2YgY2VsbHMgZm9yIGVhY2ggZ2Vub3R5cGUKZG90X3Bsb3RfZGZfcGMgPC0gKGFzLmRhdGEuZnJhbWUubWF0cml4KHByb3AudGFibGUodGFibGUoZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgZGZfbWV0YV9kYXRhJGlkZW50aXR5X2NvbWJpbmVkKSwgbWFyZ2luID0gMikpICogMTAwKQoKIyMgbWFrZSBhIGNvbHVtbiBmb3IgY2x1c3RlciBuYW1lcwpkb3RfcGxvdF9kZl9wYyRjbHVzdGVyIDwtIHJvd25hbWVzKGRvdF9wbG90X2RmX3BjKQoKIyMgbWVsdCBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nCmxpYnJhcnkocmVzaGFwZTIpCmRvdF9wbG90X2RmX3BjX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmX3BjLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9wY19tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKCiMjIG1lbHQgdGhlIHJhdyBudW1iZXIgdG9vCmRvdF9wbG90X2RmX21lbHRlZCA8LSBtZWx0KGRvdF9wbG90X2RmLCB2YXJpYWJsZS5uYW1lID0gImNsdXN0ZXIiKQpjb2xuYW1lcyhkb3RfcGxvdF9kZl9tZWx0ZWQpWzJdIDwtICJpZGVudGl0eSIKY29sbmFtZXMoZG90X3Bsb3RfZGZfbWVsdGVkKVszXSA8LSAicmF3X251bWJlciIKCiMjIG1lcmdlIHRvZ2V0aGVyCmlkZW50aWNhbChkb3RfcGxvdF9kZl9tZWx0ZWQkY2x1c3RlciwgZG90X3Bsb3RfZGZfcGNfbWVsdGVkJGNsdXN0ZXIpCmRvdF9wbG90X21lcmdlZCA8LSBjYmluZChkb3RfcGxvdF9kZl9tZWx0ZWQsIGRvdF9wbG90X2RmX3BjX21lbHRlZCkKZG90X3Bsb3RfbWVyZ2VkIDwtIGRvdF9wbG90X21lcmdlZFssYygxLDIsMyw2KV0KCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzCmRvdF9wbG90X21lcmdlZCRjbHVzdGVyIDwtIGZhY3Rvcih4ID0gZG90X3Bsb3RfbWVyZ2VkJGNsdXN0ZXIsIGxldmVscyA9IG15X2xldmVsc19zZXgpCgojIyB3aGVyZSB2YWx1ZXMgYXJlIHplcm8sIGFkZCBOQQojIyBmaW5kIHdlbGxzIHdoZXJlIGl0J3MgemVybwp6ZXJvX3ZhbHVlcyA8LSBkb3RfcGxvdF9tZXJnZWQkdmFsdWUgPT0gMApkb3RfcGxvdF9tZXJnZWQkdmFsdWVbemVyb192YWx1ZXNdIDwtIE5BCgojIyBhbHNvIGRvIGZvciByYXcgbnVtYmVyCnplcm9fdmFsdWVzIDwtIGRvdF9wbG90X21lcmdlZCRyYXdfbnVtYmVyID09IDAKZG90X3Bsb3RfbWVyZ2VkJHJhd19udW1iZXJbemVyb192YWx1ZXNdIDwtIE5BCgojIyByZW9yZGVyIHggYXhpczoKbXlfbGV2ZWxzX2dlbm90eXBlIDwtIGMoIkdDU0tPLW9vbSIsICJHQ1NLTy0yOSIsICJHQ1NLTy0yIiwgIkdDU0tPLTE5IiwgIkdDU0tPLTMiLCAiR0NTS08tMjEiLCAiR0NTS08tMTMiLCAiR0NTS08tMjgiLCAiR0NTS08tMTBfODIwIiwgIkdDU0tPLTE3IiwgIkdDU0tPLTIwIiwgIldUIiwgIldUXzEwWCIpCgpkb3RfcGxvdF9tZXJnZWQkaWRlbnRpdHkgPC0gZmFjdG9yKHggPSBkb3RfcGxvdF9tZXJnZWQkaWRlbnRpdHksIGxldmVscyA9IG15X2xldmVsc19nZW5vdHlwZSkKYGBgCgpwbG90CmBgYHtyLCBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0PSA3fQojIyBwbG90CmRvdF9wbG90X2lkZW50aXR5IDwtIGdncGxvdChkb3RfcGxvdF9tZXJnZWQsIGFlcyh5ID0gZmFjdG9yKGNsdXN0ZXIpLCB4ID0gZmFjdG9yKGlkZW50aXR5KSkpICsKICAgICAgIyMgbWFrZSBpbnRvIGEgZG90IHBsb3QKICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3VyPXZhbHVlLCBzaXplPXJhd19udW1iZXIpKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImJsdWUiLCBoaWdoPSJyZWQiLCBsaW1pdHM9YyggMCwgbWF4KGRvdF9wbG90X2RmX3BjX21lbHRlZCR2YWx1ZSkpLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgICNjaGFuZ2UgdGhlIGNvbG91cnMKICAgICAgc2NhbGVfY29sb3VyX3ZpcmlkaXMob3B0aW9uID0gImluZmVybm8iLCBndWlkZSA9ICJjb2xvdXJiYXIiLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgIHRoZW1lX2NsYXNzaWMoKSArCiAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3I9ZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yPWVsZW1lbnRfYmxhbmsoKSwgdGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xNiwgIGZhbWlseT0iQXJpYWwiKSkgKwogICAgICB5bGFiKCJDbHVzdGVyIikgKwogICAgICB4bGFiKCJJZGVudGl0eSIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIsIGFuZ2xlPTQ1LCBoanVzdD0xLCB2anVzdD0xKSwgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIsKSwgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIHBsb3QubWFyZ2luID0gdW5pdChjKDEsMywxLDMpLCAibGluZXMiKSkgKwogICAgIyMgYW5ub3RhdGUgbWFsZXMKICAgIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSA1LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBmZW1hbGVzCiAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMjAuNSkpICsKICAgICMjIGFubm90YXRlIHBoZW5vIDEKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA0LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyAyCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gNS41KSkgKyAgICAKICAgICMjIGFubm90YXRlIHBoZW5vIDMKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA3LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyA0CiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gMTEuNSkpCgojIyBwcmludApwcmludChkb3RfcGxvdF9pZGVudGl0eSkKYGBgCgojIDQuIFNsaW5nc2hvdCBhbmQgU0NNQVAgey50YWJzZXR9CgpXZSBjYW4gdGhlbiB1c2UgU2xpbmdzaG90IHRvIHBsb3QgYSBQc2V1ZG90aW1lIGFuZCBleHRyYWN0IG11dHVhbGx5IGV4Y2x1c2l2ZSBwYXJ0cyBvZiB0aGUgdHJhamVjdG9yeSAoTWFsZSBhbmQgRmVtYWxlKSBhcyB3ZWxsIGFzIHRoZSBjb21tb24gc3RhbGsgb2YgYm90aCB0cmFqZWN0b3JpZXMuCgojIyMgU2xpbmdzaG90CgpwYWNrYWdlcwpgYGB7cn0KbGlicmFyeShzbGluZ3Nob3QpCmxpYnJhcnkoc2NhdGVyKQpgYGAKCkRhdGEgSW4KYGBge3J9CiMjIGV4dHJhY3QgdGhlIGRhdGEgZnJvbSB0aGUgb2JqZWN0cyBhbmQgc2F2ZSB0byBleHBvcnQgdG8gQXJ0aHVyCmludGVncmF0ZWRfc2V4X2NvdW50cyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBhc3NheXMkaW50ZWdyYXRlZEBkYXRhCmludGVncmF0ZWRfc2V4X3BoZW5vIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YQojc2F2ZVJEUyhpbnRlZ3JhdGVkX3NleF9jb3VudHMsIGZpbGU9In4vZGF0YV90b19leHBvcnQvaW50ZWdyYXRlZF9zZXhfY291bnRzLlJEUyIpCiNzYXZlUkRTKGludGVncmF0ZWRfc2V4X3BoZW5vLCBmaWxlPSJ+L2RhdGFfdG9fZXhwb3J0L2ludGVncmF0ZWRfc2V4X3BoZW5vLlJEUyIpCiNzZXhjb3VudDwtcmVhZFJEUygiL1VzZXJzL3RhbG1hbi9Hb29nbGVcIERyaXZlL0FjdGl2ZVNhbmdlci9zZXhwYXBlci9pbnRlZ3JhdGVkX3NleF9jb3VudHMuUkRTIikKI3NleHBoZW5vPC1yZWFkUkRTKCIvVXNlcnMvdGFsbWFuL0dvb2dsZVwgRHJpdmUvQWN0aXZlU2FuZ2VyL3NleHBhcGVyL2ludGVncmF0ZWRfc2V4X3BoZW5vLlJEUyIpCnNleGNvdW50IDwtIGludGVncmF0ZWRfc2V4X2NvdW50cwpzZXhwaGVubyA8LSBpbnRlZ3JhdGVkX3NleF9waGVubwoKIyMgdGVjaG5pY2FsbHkgdGhpcyBpcyBhIHNob3J0Y3V0IGJ1dCBpdCBkaWRuJ3Qgd29yawojI2h0dHBzOi8vc2F0aWphbGFiLm9yZy9zZXVyYXQvdjMuMS9jb252ZXJzaW9uX3ZpZ25ldHRlLmh0bWwKI2NvbnZlcnQgU2V1cmF0IHRvIFNDRSBvYmplY3Q6CiNwYm1jLnNjZSA8LSBhcy5TaW5nbGVDZWxsRXhwZXJpbWVudCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCksIGFzc2F5ID0gImludGVncmF0ZWQiKQpgYGAKCiMjIyMgc2xpbmdzaG90IG9uIFBDQQpQcmVwcm9jZXNzCmBgYHtyfQojIyBtYWtlIGEgc2luZ2xlIGNlbGwgZXhwZXJpbWVudCBvYmplY3QsIHdoaWNoIGlzIHRoZSBpbnB1dCBmb3IgU2xpbmdzaG90CnNleGJyYW5jaCA8LSBTaW5nbGVDZWxsRXhwZXJpbWVudChhc3NheXMgPSBsaXN0KAogIGNvdW50cyA9IGFzLm1hdHJpeChzZXhjb3VudCksCiAgbG9nY291bnRzID0gYXMubWF0cml4KHNleGNvdW50KQopLCBjb2xEYXRhID0gc2V4cGhlbm8pCgojIyBzdWJzZXQgd2lsZC10eXBlIGNlbGxzCnNleGJyYW5jaFdUPC0gc2V4YnJhbmNoWywgY29sRGF0YShzZXhicmFuY2gpJGdlbm90eXBlID09ICJXVCJ8Y29sRGF0YShzZXhicmFuY2gpJGV4cGVyaW1lbnQgPT0gInRlbnhfNWsiXQoKIyMgY2FsY3VsYXRlIHRoZSBRQyBtZXRyaWNzCnNleGJyYW5jaFdUPC1jYWxjdWxhdGVRQ01ldHJpY3Moc2V4YnJhbmNoV1QpCgojIyBzZXQgdXAgdGhlIGNvbG91ciBwYWwKbmIuY29scyA8LSAxOCAKbXljb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJTZXQxIikpKG5iLmNvbHMpCmBgYAoKQ2FsY3VsYXRlIHRoZSBQQ1MKYGBge3J9CiMjIGNhbGN1bGF0ZSBQQ0EKcGNhIDwtIHByY29tcCh0KGFzc2F5cyhzZXhicmFuY2hXVCkkY291bnRzKSwgc2NhbGUuID0gRkFMU0UpCgojIyBzdWJzZXQgY29vcmRpbmF0ZXMKcmQxIDwtIHBjYSR4WywxOjJdCgojIyBwbG90CnBsb3QocmQxLCBjb2wgPSByZ2IoMCwwLDAsLjUpLCBwY2g9MTYsIGFzcCA9IDIpCgojIyBjbHVzdGVyIHVzaW5nIGttZWFucwojIyB5b3UgbmVlZCB0byBzZXQgYSBzZWVkIGhlcmUgdG8gZW5zdXJlIHRoZSByZXN1bHRzIGFyZSByZXByb2R1Y2libGUKc2V0LnNlZWQoNDIpCmNsMiA8LSBrbWVhbnMocmQxLCBjZW50ZXJzID0gMTMpJGNsdXN0ZXIKCiMjIHBsb3QKcGxvdChyZDEsIGNvbCA9IG15Y29sb3JzW2NsMl0sIGFzcCA9IDMsIHBjaCA9IDE2KQoKIyMgbWFrZSBhIG5pY2VyIHBsb3Qgc28gd2UgY2FuIGludGVycHJldCB0aGUgY2x1c3RlcnMKZGZfcGxvdHRpbmcgPC0gYXMuZGF0YS5mcmFtZShjYmluZChyZDEsIGNsMikpCiMjIGNoYW5nZSB0byBjaGFyYWN0ZXIgdG8gbWFrZSBpdCBkaXNjcmV0ZQpkZl9wbG90dGluZyRjbDIgPC0gYXMuY2hhcmFjdGVyKGRmX3Bsb3R0aW5nJGNsMikKIyMgcGxvdApnZ3Bsb3QoZGZfcGxvdHRpbmcsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvdXIgPSBjbDIpKSArIAogIGdlb21fcG9pbnQoKSArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gcmFpbmJvdygxMykpICsgCiAgdGhlbWVfY2xhc3NpYygpCmBgYAoKYGBge3J9CiMjIGluaXRpYWxpc2UgcGxvdCB0byBwcmV2ZW50IGVycm9yCnBsb3QubmV3KCkKCiMjIHNsaW5nc2hvdCB0byBnZXQgbGluZWFnZXMKbGluMSA8LSBnZXRMaW5lYWdlcyhyZDEsIGNsMixzdGFydC5jbHVzID0gJzgnKQoKIyMgbWFrZSBhIGN1cnZlIHRocm91Z2ggbGluZWFnZSAKY3J2MSA8LSBnZXRDdXJ2ZXMobGluMSkKCiMjIGpvaW4gcG9pbnRzIHdpdGggbGluZSBzZWdtZW50cyBhbmQgcGxvdApwbG90KHJkMSwgY29sID0gbXljb2xvcnNbY2wyXSwgYXNwID0gMywgcGNoID0gMTYpCmxpbmVzKGNydjEsIGx3ZCA9IDMsIGNvbCA9ICdibGFjaycpCgojIyBhZGQgUENBIGNvb3JkaW5hdGVzIHRvIFNDRSBvYmplY3QKcmVkdWNlZERpbXMoc2V4YnJhbmNoV1QpIDwtIFNpbXBsZUxpc3QoUENBID0gcmQxKQoKIyMgYWRkIGNsdXN0ZXJzIHRvIFNDRSBvYmplY3QKc2V4YnJhbmNoV1QkR01NPC1jbDIKCiMjIEFkZCBwc2V1ZG90aW1lcyB0byBTQ0Ugb2JqZWN0CnNleGJyYW5jaFdUJFBUX0xpbmVhZ2VGZW1hbGU8LWFzLmRhdGEuZnJhbWUoc2xpbmdQc2V1ZG90aW1lKGNydjEpKSRjdXJ2ZTEKc2V4YnJhbmNoV1QkUFRfTGluZWFnZU1hbGU8LWFzLmRhdGEuZnJhbWUoc2xpbmdQc2V1ZG90aW1lKGNydjEpKSRjdXJ2ZTIKCiMjIGFkZCBkZXNpZ25hdGlvbiB0byBTQ0Ugb2JqZWN0CnNleGJyYW5jaFdUJG1hbGU8LWlzLm5hKHNleGJyYW5jaFdUJFBUX0xpbmVhZ2VGZW1hbGUpCnNleGJyYW5jaFdUJGZlbWFsZTwtaXMubmEoc2V4YnJhbmNoV1QkUFRfTGluZWFnZU1hbGUpCnZlYyA8LSB2ZWN0b3IoKQpmb3IgKGkgaW4gMTpsZW5ndGgoc2V4YnJhbmNoV1QkbWFsZSkpIHsKaWYgKHNleGJyYW5jaFdUJG1hbGVbaV0gPT0gc2V4YnJhbmNoV1QkZmVtYWxlW2ldKSB7dmVjPC1jKHZlYywicHJlLWRldCIpfQogIGlmIChzZXhicmFuY2hXVCRtYWxlW2ldID09IFRSVUUpIHt2ZWM8LWModmVjLCJtYWxlIil9CiAgaWYgKHNleGJyYW5jaFdUJGZlbWFsZVtpXSA9PSBUUlVFKSB7dmVjPC1jKHZlYywiZmVtYWxlIil9ICAKfQoKc2V4YnJhbmNoV1Qkc2V4PC12ZWMKCiMjIHBsb3QgY29sb3VyZWQgYnkgTkVLMyAoUEJBTktBXzA2MDA2MDApCnBsb3RQQ0Eoc2V4YnJhbmNoV1Qsc2hhcGVfYnk9InNleCIsY29sb3VyX2J5PSJQQkFOS0EtMDYwMDYwMCIpCmBgYAoKIyMjIyBzbGluZ3Nob3Qgb24gVU1BUAoKYGBge3J9CiMjIGV4dHJhY3RzIG9ubHkgMTB4IGNlbGxzIAp3dF9jZWxscyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSxdKQoKIyMgbWFrZSBhIG5ldyBTZXVyYXQgb2YgdGhpcwpzZXVyYXQub2JqZWN0IDwtU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgY2VsbHMgPSB3dF9jZWxscykKCiMjIGdldCBVTUFQIGNvb3JkaW5hdGVzCnVtYXBfY29vcmRzIDwtIHNldXJhdC5vYmplY3RAcmVkdWN0aW9ucyR1bWFwb3B0aW1pc2VkX3Bvc3RfcmVwY2FAY2VsbC5lbWJlZGRpbmdzCgojIyBnZXQgY2x1c3RlcnMKI2NsdXN0ZXJzIDwtIGFzLmxpc3Qoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEkaW50ZWdyYXRlZF9zbm5fcmVzLjQpCiNuYW1lcyhjbHVzdGVycykgPC0gcm93bmFtZXMoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpCiNjbHVzdGVycyA8LSBhcy5saXN0KGNsdXN0ZXJzKQojIyBjbHVzdGVyIHVzaW5nIGttZWFucwojIyB5b3UgbmVlZCB0byBzZXQgYSBzZWVkIGhlcmUgdG8gZW5zdXJlIHRoZSByZXN1bHRzIGFyZSByZXByb2R1Y2libGUKc2V0LnNlZWQoNDIpCmNsdXN0ZXJzIDwtIGttZWFucyh1bWFwX2Nvb3JkcywgY2VudGVycyA9IDEzKSRjbHVzdGVyCgojIyBwbG90CiMjIG1ha2UgYSBuaWNlciBwbG90IHNvIHdlIGNhbiBpbnRlcnByZXQgdGhlIGNsdXN0ZXJzCmRmX3Bsb3R0aW5nIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQodW1hcF9jb29yZHMsIGNsdXN0ZXJzKSkKIyMgY2hhbmdlIHRvIGNoYXJhY3RlciB0byBtYWtlIGl0IGRpc2NyZXRlCmRmX3Bsb3R0aW5nJGNsdXN0ZXJzIDwtIGFzLmNoYXJhY3RlcihkZl9wbG90dGluZyRjbHVzdGVycykKIyMgcGxvdApnZ3Bsb3QoZGZfcGxvdHRpbmcsIGFlcyh4ID0gdW1hcG9wdGltaXNlZF8xLCB5ID0gdW1hcG9wdGltaXNlZF8yLCBjb2xvdXIgPSBjbHVzdGVycykpICsgCiAgZ2VvbV9wb2ludCgpICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSByYWluYm93KDE1KSkgKyAKICB0aGVtZV9jbGFzc2ljKCkKCgojIyBpbml0aWFsaXNlIHBsb3QgdG8gcHJldmVudCBlcnJvcgpwbG90Lm5ldygpCgojIyBzbGluZ3Nob3QgdG8gZ2V0IGxpbmVhZ2VzCmxpbmVhZ2VfdWFtcCA8LSBnZXRMaW5lYWdlcyh1bWFwX2Nvb3JkcywgY2x1c3RlcnMsIHN0YXJ0LmNsdXMgPSAnNicsIGVuZC5jbHVzID0gYygnMScsICcxMicpKQoKIyMgbWFrZSBhIGN1cnZlIHRocm91Z2ggbGluZWFnZSAKY3J2MSA8LSBnZXRDdXJ2ZXMobGluZWFnZV91YW1wKQoKIyMgam9pbiBwb2ludHMgd2l0aCBsaW5lIHNlZ21lbnRzIGFuZCBwbG90CnBsb3QodW1hcF9jb29yZHMsIGNvbCA9IG15Y29sb3JzW2NsdXN0ZXJzXSwgYXNwID0gMywgcGNoID0gMTYpCmxpbmVzKGNydjEsIGx3ZCA9IDMsIGNvbCA9ICdibGFjaycpCmBgYAoKQWRkIGRhdGEgdG8gU2V1cmF0OgpgYGB7cn0KIyMgZXh0cmFjdCBkYXRhIHRvIGFkZCB0byBTZXVyYXQKIyMgZXh0cmFjdCBjbHVzdGVycwptZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90IDwtIGRhdGEuZnJhbWUoY2x1c3RlcnNfa19tZWFuc19VTUFQID0gY2x1c3RlcnMpCiMjIEFkZCBwc2V1ZG90aW1lcwojIGNoZWNrIHRoZSBsZW5ndGggb2YgZWFjaCBicmFuY2ggdG8gc2VlIHdoaWNoIGN1cnZlIGlzIHdoaWNoIHVzaW5nOiBzdW0oaXMubmEoYXMuZGF0YS5mcmFtZShzbGluZ1BzZXVkb3RpbWUoY3J2MSkpJGN1cnZlMSkpCiMgdGhlbiBpbnNwZWN0IHVzaW5nIHRoZSBnZ3Bsb3QyIGFib3ZlIHRvIHdoZXJlIG1hbGVzIGFyZSAtIAojIHRhaWwoYXMuZGF0YS5mcmFtZShzbGluZ1BzZXVkb3RpbWUoY3J2MSkpLCAxMDApCiMgdGFpbChtZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90LCAxMDApCm1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3QkUFRfRmVtYWxlX1VNQVAgPC0gYXMuZGF0YS5mcmFtZShzbGluZ1BzZXVkb3RpbWUoY3J2MSkpJGN1cnZlMQptZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JFBUX01hbGVfVU1BUCA8LSBhcy5kYXRhLmZyYW1lKHNsaW5nUHNldWRvdGltZShjcnYxKSkkY3VydmUyCiMjIGFkZCBkZXNpZ25hdGlvbiB0byBTQ0Ugb2JqZWN0Cm1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3Qkc2V4X1VNQVAgPC0gInByZS1kZXQiCm1ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3Qkc2V4X1VNQVBbd2hpY2goaXMubmEobWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRQVF9GZW1hbGVfVU1BUCkpXSA8LSAibWFsZSIKbWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRzZXhfVU1BUFt3aGljaChpcy5uYShtZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JFBUX01hbGVfVU1BUCkpXSA8LSAiZmVtYWxlIgoKIyMgaWYgdGhlcmUgYXJlIDMgY3VydmVzIGluIHNsaW5nUHNldWRvdGltZShjcnYxKToKI21ldGFfZGF0YV90b19hZGRfZnJvbV9zbGluZ3Nob3Qkc2V4X1VNQVBbd2hpY2goaXMubmEobWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRQVF9GZW1hbGVfVU1BUCkgJiBpcy5uYShhcy5kYXRhLmZyYW1lKHNsaW5nUHNldWRvdGltZShjcnYxKSkkY3VydmUzKSldIDwtICJtYWxlIgojbWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCRzZXhfVU1BUFt3aGljaChpcy5uYShtZXRhX2RhdGFfdG9fYWRkX2Zyb21fc2xpbmdzaG90JFBUX01hbGVfVU1BUCkgJiBpcy5uYShhcy5kYXRhLmZyYW1lKHNsaW5nUHNldWRvdGltZShjcnYxKSkkY3VydmUzKSldIDwtICJmZW1hbGUiCgojIyBhZGQgY2x1c3RlcnMgdG8gU0NFIG9iamVjdAp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCA8LSBBZGRNZXRhRGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbWV0YV9kYXRhX3RvX2FkZF9mcm9tX3NsaW5nc2hvdCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQojIyBwbG90CkZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZmVhdHVyZXMgPSBjKCJQVF9GZW1hbGVfVU1BUCIsICJQVF9NYWxlX1VNQVAiKSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgoKCnBsb3Qgc2V4IGRlc2lnbmF0aW9ucwpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZ3JvdXAuYnkgPSAic2V4X1VNQVAiLCBuYS52YWx1ZSA9ICJ3aGl0ZSIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKIyMjIFNDTUFQCgpMb2FkIHBhY2thZ2UKYGBge3J9CmxpYnJhcnkoc2NtYXApCmBgYAoKU2V0IHVwIEluZGV4CmBgYHtyfQojdGhlIHJlZmVyZW5jZSBkYXRhc2V0IGlzOiBzZXhicmFuY2hXVAojIyBzZXQgdXAgYSBmZWF0dXJlIHN5bWJvbCBjb2x1bW4gaW4gdGhlIFNDRSBvYmplY3QKcm93RGF0YShzZXhicmFuY2hXVCkkZmVhdHVyZV9zeW1ib2wgPC0gcm93bmFtZXMoc2V4YnJhbmNoV1QpCgojIyBtYWtlIGFuIGlzX2V4cHIgYXNzYXkgd2hpY2ggb25seSBjb3VudHMgdmFsdWVzIHdpdGggbW9yZSB0aGFuIDAKYXNzYXkoc2V4YnJhbmNoV1QsICJpc19leHByIikgPC0gY291bnRzKHNleGJyYW5jaFdUKSA+IDAKCiMjIFNlbGVjdCB0aGUgdG9wIDUwMCBtb3N0IGltcG9ydGFudCBnZW5lcwpzZXhicmFuY2hXVCA8LSBzZWxlY3RGZWF0dXJlcyhzZXhicmFuY2hXVCwgc3VwcHJlc3NfcGxvdCA9IEZBTFNFLCBuX2ZlYXR1cmVzID0gNTAwKQoKIyMgaW5zcGVjdCBmZWF0dXJlcyBzZWxlY3RlZAp0YWJsZShyb3dEYXRhKHNleGJyYW5jaFdUKSRzY21hcF9mZWF0dXJlcykKCiMjIGNyZWF0ZSByZWZlcmVuY2UgaW5kZXgKc2V4YnJhbmNoV1QgPC0gaW5kZXhDZWxsKHNleGJyYW5jaFdUKQoKIyMgaW5zcGVjdCByZXN1bHRzCm5hbWVzKG1ldGFkYXRhKHNleGJyYW5jaFdUKSRzY21hcF9jZWxsX2luZGV4KQpsZW5ndGgobWV0YWRhdGEoc2V4YnJhbmNoV1QpJHNjbWFwX2NlbGxfaW5kZXgkc3ViY2VudHJvaWRzKQpkaW0obWV0YWRhdGEoc2V4YnJhbmNoV1QpJHNjbWFwX2NlbGxfaW5kZXgkc3ViY2VudHJvaWRzW1sxXV0pCmBgYAoKUXVlcnkgZGF0YXNldApgYGB7cn0KI3F1ZXJ5IGRhdGEgc2V0IGlzIGNhbGxlZDogc2V4YnJhbmNoCnogPC0gc2V4YnJhbmNoCgojIyBhZGQgZmVhdHVyZSBzeW1ib2wgdG8gU0NFIG9iamVjdApyb3dEYXRhKHopJGZlYXR1cmVfc3ltYm9sIDwtIHJvd25hbWVzKHopCgojIyBtYXAgY2VsbHMKc2NtYXBDZWxsX3Jlc3VsdHMgPC0gc2NtYXBDZWxsKHosIGxpc3QoeWFuID0gbWV0YWRhdGEoc2V4YnJhbmNoV1QpJHNjbWFwX2NlbGxfaW5kZXgpKQoKIyMgY29weSBvdmVyIFBDQSBjb29yZGluYXRlCmNvbERhdGEoc2V4YnJhbmNoV1QpJFBDMTwtYXMuZGF0YS5mcmFtZShyZWR1Y2VkRGltKHNleGJyYW5jaFdUKSkkUEMxCmNvbERhdGEoc2V4YnJhbmNoV1QpJFBDMjwtYXMuZGF0YS5mcmFtZShyZWR1Y2VkRGltKHNleGJyYW5jaFdUKSkkUEMyCgojIyBHZXQgbmVhcmVzdCBjZWxsIC0gd2hpY2ggaXMgbG9jYXRlZCBpbiB0aGUgZmlyc3Qgcm93IGFuZCBtYWtlIGEgbGlzdApnZXRjZWxscyA8LSBzY21hcENlbGxfcmVzdWx0cyR5YW4kY2VsbHNbMSwgXQojIyBFeHRyYWN0IG1ldGEgZGF0YSBmb3IgdGhlc2UgY2VsbHMKY2RzY2UgPC0gY29sRGF0YShzZXhicmFuY2hXVClbZ2V0Y2VsbHMsIF0KIyMgR2V0IHNpbWlsYXJpdHkgc2NvcmVzCnRvcHNpbSA8LSBzY21hcENlbGxfcmVzdWx0cyR5YW4kc2ltaWxhcml0aWVzWzEsIF0KCiMjIGFkZCBtZXRhIGRhdGEgdG8gcXVlcnkgZGF0YXNldAojIGFkZCBuZWFyZXN0IGNlbGwKeiR0b3BfcGJjZWxsIDwtIGdldGNlbGxzCiMjIGFkZCBQQ0EgY29vcmRpbmF0ZXMKeiRQQzEgPC0gY2RzY2UkUEMxCnokUEMyIDwtIGNkc2NlJFBDMgojIyBhZGQgYXNzaWduZWQgc2V4Cnokc2V4PC0gY2RzY2Ukc2V4CiMjIGFkZCBwdAp6JFBUX0xpbmVhZ2VGZW1hbGU8LSBjZHNjZSRQVF9MaW5lYWdlRmVtYWxlCnokUFRfTGluZWFnZU1hbGU8LSBjZHNjZSRQVF9MaW5lYWdlTWFsZQojIyBhZGQgc2ltaWxhcml0eSBzY29yZQp6JHRvcHNpbSA8LSB0b3BzaW0KCiMjIGluc3BlY3Qgc2ltaWxhcml0eSBzY29yZXMKaGlzdCh6JHRvcHNpbSkKCiMjIGNvdW50IGFueXRoaW5nIHdpdGggYSBzaW1pbGFyaXR5IHNjb3JlIGJlbG93IDAuNCBhcyB1bmFzc2lnbmVkCnokdG9wY2VsbF9zcFt6JHRvcHNpbSA8IDAuNF0gPC0gInVuYXNzaWduZWQiCnokdG9wY2VsbF9zcCA8LSBhcy5mYWN0b3IoeiR0b3BjZWxsX3NwKQp6JHl0PC1yZXAoImFzc2lnbmVkIixsZW5ndGgoeiR0b3BjZWxsX3NwKSkKeiR5dFt6JHRvcHNpbSA8IDAuNF0gPC0gInVuYXNzaWduZWQiCgojIyBleHRyYWN0IFBDIHNjb3JlcwpubyA8LSBhcy5kYXRhLmZyYW1lKHJlZHVjZWREaW0oc2V4YnJhbmNoV1QpWywxOjJdKQojIyBleHRyYWN0IG1ldGEgZGF0YQpudW1iZXIyIDwtIGFzLmRhdGEuZnJhbWUoY2RzY2UpCiMjIGV4dHJhY3QgdG9wIGNlbGwKbnVtYmVyMiR0b3BjZWxsX3NwIDwtIHokeXQKCiMjIHBsb3QKZ2dwbG90KG5vLCBhZXMoUEMxLCBQQzIpKSArCiBnZW9tX3BvaW50KHNpemUgPSAxLGFscGhhID0gMS8xMCkgKwogZ2VvbV9wb2ludChhZXMoeD1QQzEsIHk9UEMyLHNoYXBlPWZhY3Rvcih0b3BjZWxsX3NwKSksIGRhdGE9bnVtYmVyMiwgc2l6ZT0yLCBjb2xvdXI9ImJsYWNrIikgKwogdGhlbWVfY2xhc3NpYygpICsgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDEsMikpKwogc2NhbGVfY29sb3JfbWFudWFsKCB2YWx1ZXMgPSBjKCIwIiA9ICIjMWY3N2I0IiwiMSIgPSIjZmY3ZjBlIiwiMiIgPSIjMmNhMDJjIiwiMywwIiA9IiNkNjI3MjgiLCIzLDEiID0iIzk0NjdiZCIsIjMsMiI9IiM4YzU2NGIiLCIzLDMiPSIjZTM3N2MyIiwiNCI9IiNiY2JkMjIiLCI1Ij0iIzE3YmVjZiIsIjYiPSIjYWVjN2U4IikpICsgbGFicyh4PSJQQzEiLCB5PSJQQzIiKSAKCiMrCiMgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCksIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAsIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplICM9IDgpLCBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT06c3VuZ2xhc3NlczosIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkKCmBgYAoKIyMjIHRvIHNraXAgdGhpcyBzZWN0aW9uIGFib3ZlIGFuZCBqdXN0IGdldCB0aGUgZGF0YSBvdXRwdXQgZnJvbSBBcnRodXIncyBzY3JpcHQgd2hlcmUgUENBIGlzIHVzZWQgYXMgdGhlIGJhc2UgZGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uOgoKcmVhZCBpbiBBcnRodXIncyBkYXRhCmBgYHtyfQojIyByZWFkIGluIGRhdGEKYXRfZGF0YSA8LSByZWFkUkRTKCJ+L2RhdGEvc2V4YnJhbmNoIikKCiMjIGV4dHJhY3QgdmFsdWVzIG9mIGludGVyZXN0CmF0X21ldGFfZGF0YSA8LSBhcy5kYXRhLmZyYW1lKGF0X2RhdGFAY29sRGF0YSkKCiMjIGxvb2sgYXQgbmV3IGNvbHM6CmhlYWQodGFibGUoYXRfbWV0YV9kYXRhJHRvcF9wYmNlbGwpKQpoZWFkKHRhYmxlKGF0X21ldGFfZGF0YSR0b3BzaW0pKQpoZWFkKHRhYmxlKGF0X21ldGFfZGF0YSR0b3BjZWxsX3NwKSkKaGVhZCh0YWJsZShhdF9tZXRhX2RhdGEkeXQpKQpoZWFkKHRhYmxlKGF0X21ldGFfZGF0YSRzZXgpKQojdGFibGUoYXRfbWV0YV9kYXRhJFBUX0xpbmVhZ2VGZW1hbGUpCiN0YWJsZShhdF9tZXRhX2RhdGEkUFRfTGluZWFnZU1hbGUpCmBgYAoKQWRkIG1ldGEgZGF0YSB0byBTZXVyYXQgb2JqZWN0CmBgYHtyfQpjb2xuYW1lc190b19hZGRfdG9fbWV0YV9kYXRhIDwtIGMoInRvcF9wYmNlbGwiLCAidG9wc2ltIiwgInRvcGNlbGxfc3AiLCAieXQiLCAic2V4IiwgIlBUX0xpbmVhZ2VGZW1hbGUiLCAiUFRfTGluZWFnZU1hbGUiKQoKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIG1ldGFkYXRhID0gYXRfbWV0YV9kYXRhWyx3aGljaChjb2xuYW1lcyhhdF9tZXRhX2RhdGEpICVpbiUgY29sbmFtZXNfdG9fYWRkX3RvX21ldGFfZGF0YSldLCBjb2wubmFtZSA9IGMoImF0X3RvcF9wYmNlbGwiLCAiYXRfdG9wc2ltIiwgImF0X3RvcGNlbGxfc3AiLCAiYXRfeXQiLCAiYXRfc2V4IiwgImF0X1BUX0xpbmVhZ2VGZW1hbGUiLCAiYXRfUFRfTGluZWFnZU1hbGUiKSkKCiMjIHRvIHJlbW92ZSBjb2x1bW5zIGluIG1ldGFkYXRhOgojdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhWzEzNjoxNDRdIDwtIE5VTEwKI3RlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVtbJ05BTUVfT0ZfQ09MJ11dIDwtIE5VTEwKYGBgCgpQbG90IHNleGVzCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJhdF9zZXgiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTB9CiMjIHRoZSBzbGluZ3Nob3QgcHQgdmFsdWVzIGhhdmUgTkFzIGZvciBlLmcuIG1hbGUgY2VsbHMgaW4gdGhlIFBUX0xpbmVhZ2VGZW1hbGUsIHdlIGNhbiBkZWFsIHdpdGggdGhpcyBsYXRlciwgYnV0IGZvciBub3csIHdlIHdpbGwganVzdCBpZ25vcmUgdGhpcyBhcyBEaW1wbG90IHdpbGwgbm90IHBsb3QgTkEgdmFsdWVzCiNzdW0oaXMubmEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGF0X1BUX0xpbmVhZ2VNYWxlKSkKI3N1bShpcy5uYSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkYXRfUFRfTGluZWFnZUZlbWFsZSkpCgojIyBwbG90CkZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZmVhdHVyZXMgPSBjKCJhdF9QVF9MaW5lYWdlRmVtYWxlIiwgImF0X1BUX0xpbmVhZ2VNYWxlIikpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKCiMjIyMgQ29tcGFyaXNvbiBvZiBjbHVzdGVyIHdheSBvZiBjYWxsaW5nIG1hbGVzIGFuZCBmZW1hbGVzIHZzLiBzbGluZ3Nob3Q6CgpgYGB7cn0KdGFibGUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCkKCm1hbGVfY2x1c3RlcnMgPC0gYygiMTMiLCAiNSIsICIxMSIsICIyNSIsICIxIiwgIjE3IiwgIjEwIiwgIjI0IiwgIjE0IiwgIjI3IiwgIjE5IikKZmVtYWxlX2NsdXN0ZXJzIDwtIGMoIjE2IiwgIjIyIiwgIjIzIiwgIjE1IiwgIjIxIiwgIjMwIiwgIjQiLCAiMyIsICIxOCIsICI3IiwgIjgiLCAiNiIsICIyMCIsICIxMiIsICIyNiIpCmFzZXhfY2x1c3RlcnMgPC0gYygiMCIsICI5IiwgIjI4IiwgIjIiLCAiMjkiKQoKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleF9kZXNpZ25hdGlvbl91c2luZ19jbHVzdGVycyA8LSBOQQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4X2Rlc2lnbmF0aW9uX3VzaW5nX2NsdXN0ZXJzW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgJWluJSBtYWxlX2NsdXN0ZXJzKV0gPC0gIk1hbGUiCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXhfZGVzaWduYXRpb25fdXNpbmdfY2x1c3RlcnNbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyAlaW4lIGZlbWFsZV9jbHVzdGVycyldIDwtICJGZW1hbGUiCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXhfZGVzaWduYXRpb25fdXNpbmdfY2x1c3RlcnNbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycyAlaW4lIGFzZXhfY2x1c3RlcnMpXSA8LSAiUHJlLWRldCIKCnRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXhfZGVzaWduYXRpb25fdXNpbmdfY2x1c3RlcnMpCmBgYAoKYGBge3J9CnRhYmxlKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXgsIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXhfZGVzaWduYXRpb25fdXNpbmdfY2x1c3RlcnMpCmBgYAoKUGxvdCBzZXhlcwpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDd9CkRpbVBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBsYWJlbC5zaXplID0gNSwgcHQuc2l6ZSA9IDAuNSwgZ3JvdXAuYnkgPSAic2V4IikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZChucm93PTMsYnlyb3c9VFJVRSwgb3ZlcnJpZGUuYWVzID0gbGlzdChzaXplPTQpKSkKYGBgCgpQbG90IHNleGVzCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KRGltUGxvdCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJzZXhfZGVzaWduYXRpb25fdXNpbmdfY2x1c3RlcnMiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGd1aWRlcyhjb2xvdXI9Z3VpZGVfbGVnZW5kKG5yb3c9MyxieXJvdz1UUlVFLCBvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKQpgYGAKCmNvcnJlbGF0aW9uIG9mIG1vbm9jbGUgUFQgYW5kIAoKYGBge3J9CiMjIGV4dHJhY3QgcHNldWRvdGltZSB2YWx1ZXM6CnB0X3ZhbHVlcyA8LSBhcy5kYXRhLmZyYW1lKHBzZXVkb3RpbWUobW9ub2NsZS5vYmplY3QsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIpKQpwdF92YWx1ZXMkY2VsbF9uYW1lIDwtIHJvd25hbWVzKHB0X3ZhbHVlcykKbWV0YV9kYXRhX2RmIDwtIGFzLmRhdGEuZnJhbWUobW9ub2NsZS5vYmplY3RAY29sRGF0YSkKbWV0YV9kYXRhX2RmJGNlbGxfbmFtZSA8LSByb3duYW1lcyhtZXRhX2RhdGFfZGYpCm1ldGFfZGF0YV9kZiA8LSBtZXJnZShtZXRhX2RhdGFfZGYsIHB0X3ZhbHVlcywgYnkgPSAiY2VsbF9uYW1lIikKbmFtZXMobWV0YV9kYXRhX2RmKVsxNDJdPC0gInB0IgoKbWFsZV9wdF9jb3JyZWxhdGlvbl9kZiA8LSBtZXRhX2RhdGFfZGZbd2hpY2gobWV0YV9kYXRhX2RmJGNlbGxfbmFtZSAlaW4lIG1hbGVfY2VsbHMpLCBdCmZlbWFsZV9wdF9jb3JyZWxhdGlvbl9kZiA8LSBtZXRhX2RhdGFfZGZbd2hpY2gobWV0YV9kYXRhX2RmJGNlbGxfbmFtZSAlaW4lIGZlbWFsZV9jZWxscyksIF0KCmdncGxvdChtYWxlX3B0X2NvcnJlbGF0aW9uX2RmLCBhZXMoeCA9IFBUX0xpbmVhZ2VNYWxlLCB5ID0gcHQsIGNvbG91ciA9IHNleCkpICsgCiAgZ2VvbV9wb2ludCgpICsgIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICB0aGVtZV9jbGFzc2ljKCkKCmdncGxvdChmZW1hbGVfcHRfY29ycmVsYXRpb25fZGYsIGFlcyh4ID0gUFRfTGluZWFnZUZlbWFsZSwgeSA9IHB0LCBjb2xvdXIgPSBzZXgpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICB0aGVtZV9jbGFzc2ljKCkKYGBgCgpgYGB7cn0KZ2dwbG90KG1hbGVfcHRfY29ycmVsYXRpb25fZGYsIGFlcyh4ID0gUFRfRmVtYWxlX1VNQVAsIHkgPSBwdCkpICsgCiAgZ2VvbV9wb2ludCgpICsgIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICB0aGVtZV9jbGFzc2ljKCkKYGBgCgoKIyA2LiBNb25vY2xlIG9uIHNleCBjZWxscyB7LnRhYnNldH0KCiMjIGNhbGN1bGF0ZSBwc2V1ZG90aW1lIGFuZCBtb2R1bGVzCgojIyMjIFByZXBhcmF0aW9uCmBgYHtyfQojIyBsb2FkIHBhY2thZ2UKI2xpYnJhcnkobW9ub2NsZTMpCgojIyBoZWxwIHdhcyBvYnRhaW5lZCBmcm9tIGhlcmUKIyMgaHR0cHM6Ly9naXRodWIuY29tL3NhdGlqYWxhYi9zZXVyYXQvaXNzdWVzLzE2NTgKCiMjIGV4dHJhY3QgZGF0YQojIyB0aGlzIGV4dHJhY3RzIHd0IG9ubHkgY2VsbHMKI3d0X2NlbGxzIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUIiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksXSkKCiMjIGV4dHJhY3RzIG9ubHkgMTB4IGNlbGxzIAp3dF9jZWxscyA8LSByb3duYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSxdKQoKIyMgbWFrZSBhIG5ldyBTZXVyYXQgb2YgdGhpcwpzZXVyYXQub2JqZWN0IDwtU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgY2VsbHMgPSB3dF9jZWxscykKCiMjIG1ha2UgbmV3IGNvdW50cyBhbmQgcGhlbm86CiMjIHRoZSByZWFzb24gd2UgdXNlIHRoZSBpbnRlZ3JhdGVkIGFuZCB0aGVuIHN1YnNldHRlZCBpcyBiZWNhdXNlIHRoZXNlIGNlbGxzIGhhdmUgYmVlbiBub3JtYWxpc2VkIHdoZXJlYXMgdGhlIGNlbGxzIGluIHBiX3NleF9maWx0ZXJlZCBoYXZlIG5vdCBiZWVuIG5vcm1hbGlzZWQgKHdlbGwgdGhleSBoYXZlIGJ1dCB3aXRoIGRvdWJsZXRzIGluIHRoZW0pCmRhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShzZXVyYXQub2JqZWN0LCBhc3NheSA9ICJSTkEiLCBzbG90ID0gImRhdGEiKSksICdzcGFyc2VNYXRyaXgnKQpwZCA8LSBkYXRhLmZyYW1lKHNldXJhdC5vYmplY3RAbWV0YS5kYXRhKQoKIyMga2VlcCBvbmx5IHRoZSBjb2x1bW5zIHRoYXQgYXJlIHJlbGV2YW50CiNwRGF0YSA8LSBwZCAlPiUgc2VsZWN0KG9yaWcuaWRlbnQsIG5Db3VudF9STkEsIG5GZWF0dXJlX1JOQSkKZkRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3cubmFtZXMoZGF0YSksIHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhkYXRhKSkKCiMjIENvbnN0cnVjdCBtb25vY2xlIGNkcwptb25vY2xlLm9iamVjdCA8LSBuZXdfY2VsbF9kYXRhX3NldChleHByZXNzaW9uX2RhdGEgPSBkYXRhLCBjZWxsX21ldGFkYXRhID0gcGQsIGdlbmVfbWV0YWRhdGEgPSBmRGF0YSkKCiMjIHByZXByb2Nlc3MKbW9ub2NsZS5vYmplY3QgPSBwcmVwcm9jZXNzX2Nkcyhtb25vY2xlLm9iamVjdCwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikKIyMjIGlmIHVzaW5nIGludGVncmF0ZWQgZGF0YToKIyBub3JtX21ldGhvZCA9ICJub25lIiwgYWxpZ25tZW50X2dyb3VwID0gIn4gZXhwZXJpbWVudCIKCnBsb3RfcGNfdmFyaWFuY2VfZXhwbGFpbmVkKG1vbm9jbGUub2JqZWN0KQoKbW9ub2NsZS5vYmplY3QgPSByZWR1Y2VfZGltZW5zaW9uKG1vbm9jbGUub2JqZWN0LCByZWR1Y3Rpb25fbWV0aG9kID0gIlVNQVAiLCBwcmVwcm9jZXNzX21ldGhvZCA9ICJQQ0EiLCB1bWFwLm1ldHJpYyA9ICJldWNsaWRlYW4iLCB1bWFwLm5fbmVpZ2hib3JzID0gNTAsIHVtYXAubWluX2Rpc3QgPSAwLjUsIHZlcmJvc2UgPSBGQUxTRSkKCnBsb3RfY2VsbHMobW9ub2NsZS5vYmplY3QsIGNvbG9yX2NlbGxzX2J5PSJleHBlcmltZW50IikKYGBgCgojIyMjIEdyYXBoIExlYXJuaW5nCmBgYHtyfQojIyBhZGQgVU1BUCBmcm9tIFNldXJhdAptb25vY2xlLm9iamVjdEBpbnRfY29sRGF0YUBsaXN0RGF0YSRyZWR1Y2VkRGltc0BsaXN0RGF0YVtbIlVNQVAiXV0gPC0gc2V1cmF0Lm9iamVjdEByZWR1Y3Rpb25zW1sidW1hcCJdXUBjZWxsLmVtYmVkZGluZ3MKCiMjIGNsdXN0ZXIKbW9ub2NsZS5vYmplY3QgPSBjbHVzdGVyX2NlbGxzKG1vbm9jbGUub2JqZWN0KQoKIyMgcGxvdApwbG90X2NlbGxzKG1vbm9jbGUub2JqZWN0LCBjb2xvcl9jZWxsc19ieT0iY2x1c3RlciIsIGdyb3VwX2NlbGxzX2J5PSJwYXJ0aXRpb24iKQoKIyMgbWFwIHBzZXVkb3RpbWUKbW9ub2NsZS5vYmplY3QgPSBsZWFybl9ncmFwaChtb25vY2xlLm9iamVjdCwgbGVhcm5fZ3JhcGhfY29udHJvbD1saXN0KG5jZW50ZXI9NDAwKSwgdXNlX3BhcnRpdGlvbiA9IEZBTFNFKQojIGxlYXJuX2dyYXBoX2NvbnRyb2w9bGlzdChuY2VudGVyPTUwMCkgLSBwbGF5IHdpdGggdGhpcyBwYXJhbWV0ZXIKCiMjIFBsb3QgY2VsbHMKcGxvdF9jZWxscyhtb25vY2xlLm9iamVjdCwgY29sb3JfY2VsbHNfYnk9InBhcnRpdGlvbiIsIGdyb3VwX2NlbGxzX2J5PSJwYXJ0aXRpb24iKSAKYGBgCgojIyMjIFBzZXVkb3RpbWUgQ2FsY3VsYXRpb24KYGBge3J9CiMjIGEgaGVscGVyIGZ1bmN0aW9uIHRvIGlkZW50aWZ5IHRoZSByb290IHByaW5jaXBhbCBwb2ludHM6CmdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZSA8LSBmdW5jdGlvbihjZHMsIHRpbWVfYmluPSIwIil7CiAgY2VsbF9pZHMgPC0gd2hpY2goY29sRGF0YShjZHMpWywgInNldXJhdF9jbHVzdGVycyJdID09IHRpbWVfYmluKQogIGNsb3Nlc3RfdmVydGV4IDwtCiAgY2RzQHByaW5jaXBhbF9ncmFwaF9hdXhbWyJVTUFQIl1dJHByX2dyYXBoX2NlbGxfcHJval9jbG9zZXN0X3ZlcnRleAogIGNsb3Nlc3RfdmVydGV4IDwtIGFzLm1hdHJpeChjbG9zZXN0X3ZlcnRleFtjb2xuYW1lcyhjZHMpLCBdKQogIHJvb3RfcHJfbm9kZXMgPC0KICBpZ3JhcGg6OlYocHJpbmNpcGFsX2dyYXBoKGNkcylbWyJVTUFQIl1dKSRuYW1lW2FzLm51bWVyaWMobmFtZXMKICAod2hpY2gubWF4KHRhYmxlKGNsb3Nlc3RfdmVydGV4W2NlbGxfaWRzLF0pKSkpXQogIAogIHJvb3RfcHJfbm9kZXMKfQoKIyMgT3JkZXIgdGhlIGNlbGxzIGFuZCBjYWNsdWxhdGUgcHNldWRvdGltZQptb25vY2xlLm9iamVjdCA9IG9yZGVyX2NlbGxzKG1vbm9jbGUub2JqZWN0LCByb290X3ByX25vZGVzPWdldF9lYXJsaWVzdF9wcmluY2lwYWxfbm9kZShtb25vY2xlLm9iamVjdCkpCgojIyBQbG90CnBsb3RfY2VsbHMobW9ub2NsZS5vYmplY3QsIGNvbG9yX2NlbGxzX2J5ID0gInBzZXVkb3RpbWUiLCBsYWJlbF9jZWxsX2dyb3Vwcz1GQUxTRSwgY2VsbF9zaXplID0gMikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgbGFicyh0aXRsZSA9ICJQc2V1ZG90aW1lIikgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpgYGAKCiMjIyMgQ2hlY2sgaG93IHdlbGwgaXQgY29ycmVsYXRlcyB3aXRoIHRoZSBvcmlnaW5hbCBwc2V1ZG90aW1lCgp3aGVuIHBzZXVkb3RpbWUgd2FzIGNhbGN1YWx0ZWQgb24gdGhlIHdob2xlIG9iamVjdAoKYGBge3J9CmxpYnJhcnkoZ2dwdWJyKQojIyBleHRyYWN0IHBzZXVkb3RpbWUgdmFsdWVzOgpwdF92YWx1ZXNfbmV3IDwtIGFzLmRhdGEuZnJhbWUocHNldWRvdGltZShtb25vY2xlLm9iamVjdCwgcmVkdWN0aW9uX21ldGhvZCA9ICJVTUFQIikpCnB0X3ZhbHVlc19uZXckY2VsbF9uYW1lIDwtIHJvd25hbWVzKHB0X3ZhbHVlc19uZXcpCm1ldGFfZGF0YV9kZiA8LSBhcy5kYXRhLmZyYW1lKG1vbm9jbGUub2JqZWN0QGNvbERhdGEpCm1ldGFfZGF0YV9kZiRjZWxsX25hbWUgPC0gcm93bmFtZXMobWV0YV9kYXRhX2RmKQptZXRhX2RhdGFfZGYgPC0gbWVyZ2UobWV0YV9kYXRhX2RmLCBwdF92YWx1ZXNfbmV3LCBieSA9ICJjZWxsX25hbWUiKQpuYW1lcyhtZXRhX2RhdGFfZGYpWzE0NV08LSAicHQiCgpnZ3Bsb3QobWV0YV9kYXRhX2RmLCBhZXMoeCA9IG9sZF9wdF92YWx1ZXMsIHkgPSBwdCwgY29sb3VyID0gc2V4X1VNQVApKSArIAogIGdlb21fcG9pbnQoKSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgdGhlbWVfY2xhc3NpYygpICsgc3RhdF9jb3IobWV0aG9kID0gInBlYXJzb24iKQpgYGAKCiMjIyMgSXNvbGF0ZSBCcmFuY2hlcwoKYGBge3J9CiMjIGFjY2VzcyB0aGUgY2xvc2VzdCBwcmluY2lwYWwgZ3JhcGggbm9kZSB2ZXJ0ZXggZm9yIGVhY2ggY2VsbCBhbmQgYXNzaWduIGl0IGFzIGEgY29sdW1uIGluIHlvdXIgY29sRGF0YSB0YWJsZSB1c2luZwpjb2xEYXRhKG1vbm9jbGUub2JqZWN0KSRjbG9zZXN0X3ZlcnRleCA8LSBtb25vY2xlLm9iamVjdEBwcmluY2lwYWxfZ3JhcGhfYXV4W1siVU1BUCJdXSRwcl9ncmFwaF9jZWxsX3Byb2pfY2xvc2VzdF92ZXJ0ZXhbLDFdCgojIyBwbG90CnBsb3RfY2VsbHMobW9ub2NsZS5vYmplY3QsIGNvbG9yX2NlbGxzX2J5ID0gImNsb3Nlc3RfdmVydGV4IiwgbGFiZWxfY2VsbF9ncm91cHMgPSBGQUxTRSkKYGBgCgojIyMjIE1vZHVsZSBDb25zdHJ1Y3Rpb24KYGBge3J9CiMjIGZpbmQgZ2VuZXMgdGhhdCBjaGFuZ2UgYXMgYSBmdW5jdGlvbiBvZiBwdDoKbW9ub2NsZS5vYmplY3RfcHJfdGVzdF9yZXMgPC0gZ3JhcGhfdGVzdChtb25vY2xlLm9iamVjdCwgbmVpZ2hib3JfZ3JhcGg9InByaW5jaXBhbF9ncmFwaCIsIGNvcmVzPTgpCgojIyBmaW5kIHNpZ25pZmljYW50IGdlbmVzCnByX2RlZ19pZHMgPC0gcm93Lm5hbWVzKHN1YnNldChtb25vY2xlLm9iamVjdF9wcl90ZXN0X3JlcywgcV92YWx1ZSA8IDAuMDEpKQoKIyMgY29sbGVjdCBpbnRvIG1vZHVsZXMKZ2VuZV9tb2R1bGVfZGZfc2V4IDwtIGZpbmRfZ2VuZV9tb2R1bGVzKG1vbm9jbGUub2JqZWN0W3ByX2RlZ19pZHMsXSwgcmVzb2x1dGlvbj1jKDEwXnNlcSgtNiwyKSkpCgojIyBob3cgbWFueSBnZW5lcyBpbiBtb2R1bGVzPwpkaW0oZ2VuZV9tb2R1bGVfZGZfc2V4KQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CnBhc3RlKCJ0aGVyZSBhcmUiLCBsZW5ndGgobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpKSwgIm1vZHVsZXMiKQpgYGAKCiMjIFBsb3QgTW9kdWxlcwoKIyMjIyBHZW5lcmFsIE1vZHVsZSBDaGFyYWN0ZXJpc3RpY3MKCk1ha2UgYSBkYXRhZnJhbWUgdG8gcGxvdCBieSBhZ2dyZWdhdGluZyBjbHVzdGVycyB2cy4gbW9kdWxlcwpgYGB7cn0KIyMgbWFrZSBjZWxsIGdyb3VwIGRmCmNlbGxfZ3JvdXBfZGYgPC0gdGliYmxlOjp0aWJibGUoY2VsbD1yb3cubmFtZXMoY29sRGF0YShtb25vY2xlLm9iamVjdCkpLCBjZWxsX2dyb3VwPWNvbERhdGEobW9ub2NsZS5vYmplY3QpJHNldXJhdF9jbHVzdGVycykKCiMjIG1ha2UgcGxvdHRpbmcgZGYKYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBnZW5lX21vZHVsZV9kZl9zZXgsIGNlbGxfZ3JvdXBfZGYpCmBgYAoKRmluZCBvdXQgaG93IG1hbnkgZ2VuZXMgdGhlcmUgYXJlIHBlciB0b3RhbCBzbyB3ZSBjYW4gYWRkIHRoaXMgdG8gdGhlIHBsb3QKYGBge3J9CiMjIGhvdyBtYW55IGdlbmVzIHBlciBtb2R1bGU/CmdlbmVzX3Blcl9tb2R1bGUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlKSkKZ2VuZXNfcGVyX21vZHVsZQpgYGAKCkZpbmQgb3V0IHdoaWNoIG1vZHVsZXMgb3VyIG11dGFudCBnZW5lcyByZXNpZGUgaW4KYGBge3J9CiMjIGNyZWF0ZSBhIGxpc3Qgb2Ygb3VyIG11dGFudCBnZW5lIElEcwpsaXN0X29mX211dGFudF9nZW5lcyA8LSBjKCJQQkFOS0EtMDgyODAwMCIsICJQQkFOS0EtMTMwMjcwMCIsICJQQkFOS0EtMTQ0NzkwMCIsICJQQkFOS0EtMDEwMjQwMCIsICJQQkFOS0EtMDcxNjUwMCIsICJQQkFOS0EtMTQzNTIwMCIsICJQQkFOS0EtMTQxODEwMCIsICJQQkFOS0EtMTE0NDgwMCIsICJQQkFOS0EtMDkwMjMwMCIsICJQQkFOS0EtMDQxMzQwMCIsICJQQkFOS0EtMTQ1NDgwMCIpCgojIyBtYWtlIGEgZGF0YWZyYW1lIHRvIGNvbnZlcnQgdGhlIGdlbmUgSURzIGludG8gYWN0dWFsIElEcwpkZl9tdXRhbnRfaWRzIDwtIGFzLmRhdGEuZnJhbWUodW5pcXVlKGNiaW5kKHRlbngubXV0YW50LmludGVncmF0ZWRAbWV0YS5kYXRhJGlkZW50aXR5X2dlbmVfdXBkYXRlZCwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZEBtZXRhLmRhdGEkaWRlbnRpdHlfdXBkYXRlZCkpKVstYygxLCA0KSxdCiMgcmVtb3ZlIHRoZSAiODIwIiBiaXQgb24gMTAKZGZfbXV0YW50X2lkcyRWMSA8LSBnc3ViKCJfODIwIiwgIiIsIGRmX211dGFudF9pZHMkVjEpCiMgY2hhbmdlIHRoZSB1bmRlcnNjb3JlIChfKSB0byBhIGRhc2ggKC0pIGluIGdlbmUgSURzCmRmX211dGFudF9pZHMkVjEgPC0gZ3N1YigiXyIsICItIiwgZGZfbXV0YW50X2lkcyRWMSkKbmFtZXMoZGZfbXV0YW50X2lkcykgPC0gYygiZ2VuZV9JRCIsICJtdXRhbnRfaWRlbnRpdHkiKQoKIyMgc3Vic2V0IG1vZHVsZXMgZGYgdG8gaW5jbHVkZSBvbmx5IG11dGFudCBnZW5lIElEcwpkZl9tdXRhbnRfZ2VuZV9tb2R1bGVzIDwtIGFzLmRhdGEuZnJhbWUoZ2VuZV9tb2R1bGVfZGZfc2V4W3doaWNoKGdlbmVfbW9kdWxlX2RmX3NleCRpZCAlaW4lIGxpc3Rfb2ZfbXV0YW50X2dlbmVzKSxdKQpuYW1lcyhkZl9tdXRhbnRfZ2VuZV9tb2R1bGVzKVsxXSA8LSAiZ2VuZV9JRCIKCiMjIG1lcmdlIGRhdGFmcmFtZXMKZGZfbXV0YW50X2dlbmVfbW9kdWxlcyA8LSBtZXJnZShkZl9tdXRhbnRfZ2VuZV9tb2R1bGVzLCBkZl9tdXRhbnRfaWRzLCBieSA9ICJnZW5lX0lEIikKCiMjIEluc3BlY3QKZGZfbXV0YW50X2dlbmVfbW9kdWxlcwpgYGAKCnNvIG1vZHVsZXMgb2YgaW50ZXJlc3QgYXJlOgpgYGB7cn0KdGFibGUoZGZfbXV0YW50X2dlbmVfbW9kdWxlcyRtb2R1bGUpCmBgYAoKV2hpY2ggbW9kdWxlcyBkbyBvdGhlciBnZW5lcyBvZiBpbnRlcmVzdCBsaWUgaW4/OgpgYGB7cn0KIyMgbGFuZG1hcmsgZ2VuZXMgKGdlbmVzIG9mIGludGVyZXN0KQojIEFQMkcgLSBQQkFOS0EtMTQzNzUwMAojIEFQMiAtIFBCQU5LQS0wOTA5NjAwIC0gZnJvbSBwb3JhbiBwYXBlcgojIEFQMkctMiAtIFBCQU5LQS0xMDM0MzAwIAojIGNjcDIgLSAiUEJBTktBLTEzMTk1MDAiIC0gZmVtYWxlIDgyMAojIE1HMSAtICJQQkFOS0EtMDQxNjEwMCIgLSBtYWxlIDgyMAoKIyMgY3JlYXRlIGEgbGlzdCBvZiBsYW5kbWFyayBnZW5lcwpsaXN0X29mX2xhbmRtYXJrX2dlbmVzIDwtIGMoIlBCQU5LQS0xNDM3NTAwIiwgIlBCQU5LQS0wOTA5NjAwIiwiUEJBTktBLTEwMzQzMDAiLCAiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiKQoKIyMgbWFrZSBkYXRhZnJhbWUKZGZfbGFuZG1hcmtfZ2VuZV9tb2R1bGVzIDwtIGdlbmVfbW9kdWxlX2RmX3NleFt3aGljaChnZW5lX21vZHVsZV9kZl9zZXgkaWQgJWluJSBsaXN0X29mX2xhbmRtYXJrX2dlbmVzKSxdCgojIyBpbnNwZWN0CmRmX2xhbmRtYXJrX2dlbmVfbW9kdWxlcwpgYGAKCnBsb3Qgb3V0IG1vZHVsZXMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gN30KIyMgbWFrZSBhZ2dyZWdhdGVkIGRmIGFnYWluIHNvIHlvdSBjYW4gZWRpdCBpdAphZ2dfbWF0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgY2VsbF9ncm91cF9kZikKCiMjIGggY2x1c3QgdGhlIGFnZ3JlZ2F0ZWQgbWF0cml4Cm1vZHVsZV9kZW5kcm8gPC0gaGNsdXN0KGRpc3QoYWdnX21hdCkpCgojIyB1c2UgdGhlc2UgY2x1c3RlcnMgdG8gcmVvcmRlciB0aGUgbW9kdWxlcwpnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlIDwtIGZhY3RvcihnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlLCBsZXZlbHMgPSByb3cubmFtZXMoYWdnX21hdClbbW9kdWxlX2RlbmRybyRvcmRlcl0pCgojIyBwbG90CnBsb3RfY2VsbHMobW9ub2NsZS5vYmplY3QsIGdlbmVzPWdlbmVfbW9kdWxlX2RmX3NleCAlPiUgZmlsdGVyKG1vZHVsZSAlaW4lIGMoMToyMCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsX2NlbGxfZ3JvdXBzPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX3RvX3JhbmdlID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93X3RyYWplY3RvcnlfZ3JhcGg9RkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfbGFiZWxfc2l6ZSA9IDgpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSAiZXhwcmVzc2lvbiIsIG9wdGlvbiA9ICJDIiwgYWxwaGEgPSAxKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29vcmRfZml4ZWQoKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfdm9pZCgpICsKICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpgYGB7cn0KIyMgbWFrZSBhIGRhdGFmcmFtZSBvZiBnZW5lcyBwZXIgbW9kdWxlCmdlbmVzX3Blcl9tb2R1bGUgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlKSkKYGBgCgpNYWtlIGFubm90YXRpb25zIHRvIGFkZCB0byB0aGUgaGVhdG1hcApgYGB7cn0KIyMgY2hhbmdlIG5hbWVzIGZvciByb3cgbmFtZXMgdG8gaW5jbHVkZSAibW9kdWxlICIgYXQgdGhlIGJlZ2luaW5nIG9mIHRoZW0Kcm93Lm5hbWVzKGFnZ19tYXQpIDwtIHN0cmluZ3I6OnN0cl9jKCJNb2R1bGUgIiwgcm93Lm5hbWVzKGFnZ19tYXQpKQoKIyMgYWRkIG51bWJlciBvZiBjZWxscyB0byB0aGUgcm93bmFtZXMgZm9yIHRoZSBtb2R1bGUKZm9yKGkgaW4gc2VxX2Fsb25nKGdlbmVzX3Blcl9tb2R1bGUkRnJlcSkpewogIHJvdy5uYW1lcyhhZ2dfbWF0KVtpXSA8LSBzdHJpbmdyOjpzdHJfYyhyb3cubmFtZXMoYWdnX21hdClbaV0sIiAobiA9ICIgLGdlbmVzX3Blcl9tb2R1bGUkRnJlcVtpXSwgIikiKQp9CgojIyBjcmVhdGUgYW5ub3RhdGlvbiBvZiBjbHVzdGVycyBmb3IgcGhlYXRtYXA6CmNsdXN0ZXJfYW5ubyA8LSBkYXRhLmZyYW1lKGNsdXN0ZXIgPSB1bmlxdWUoY29sRGF0YShtb25vY2xlLm9iamVjdCkkc2V1cmF0X2NsdXN0ZXJzKSkKcm93Lm5hbWVzKGNsdXN0ZXJfYW5ubykgPC0gY2x1c3Rlcl9hbm5vJGNsdXN0ZXIKCiMjIGNsdXN0ZXJzIHdlcmUgZGVmaW5lZCBlYXJsaWVyIGFzOgptYWxlX2NsdXN0ZXJzIDwtIGMoIjEzIiwgIjUiLCAiMTEiLCAiMjUiLCAiMSIsICIxNyIsICIxMCIsICIyNCIsICIxNCIsICIyNyIsICIxOSIpCmZlbWFsZV9jbHVzdGVycyA8LSBjKCIxNiIsICIyMiIsICIyMyIsICIxNSIsICIyMSIsICIzMCIsICI0IiwgIjMiLCAiMTgiLCAiNyIsICI4IiwgIjYiLCAiMjAiLCAiMTIiLCAiMjYiKQphc2V4X2NsdXN0ZXJzIDwtIGMoIjAiLCAiOSIsICIyOCIsICIyIiwgIjI5IikKCiMjIGFkZCBpZGVudGl0aWVzIHRvIHRoZSBjb2x1bW4KY2x1c3Rlcl9hbm5vJGdyb3VwIDwtIE5BCmNsdXN0ZXJfYW5ubyRncm91cFt3aGljaChjbHVzdGVyX2Fubm8kY2x1c3RlciAlaW4lIGFzZXhfY2x1c3RlcnMpXSA8LSAiQXNleHVhbCIKY2x1c3Rlcl9hbm5vJGdyb3VwW3doaWNoKGNsdXN0ZXJfYW5ubyRjbHVzdGVyICVpbiUgbWFsZV9jbHVzdGVycyldIDwtICJNYWxlIgpjbHVzdGVyX2Fubm8kZ3JvdXBbd2hpY2goY2x1c3Rlcl9hbm5vJGNsdXN0ZXIgJWluJSBmZW1hbGVfY2x1c3RlcnMpXSA8LSAiRmVtYWxlIgpjbHVzdGVyX2Fubm8gPC0gY2x1c3Rlcl9hbm5vWyAsIDIsIGRyb3AgPSBGQUxTRV0KY2x1c3Rlcl9hbm5vCgojIyBhZGQgbWVkaWFuIHBzZXVkb3RpbWUgcGVyIGNsdXN0ZXIKIyMgaGVscCBoZXJlOgojIyBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy81NDM2MDg1NS9jYWxjdWxhdGUtbWVhbi1mb3ItY29sdW1uLWdyb3VwZWQtYnktdmFsdWVzLW9mLXR3by1vdGhlci1jb2x1bW5zCiMjIG1ha2Ugc3Vic2V0dGVkIGRhdGFmcmFtZQpkZl9tZWRpYW5fcHQgPC0gbWV0YV9kYXRhX2RmWyAsYygicHQiLCAic2V1cmF0X2NsdXN0ZXJzIildCiMjIGFwcGx5IGFjcm9zcyBkYXRhZnJhbWUgdG8gZ2V0IG1lZGlhbgptZWFuLmRmMSA8LSB0YXBwbHkoZGZfbWVkaWFuX3B0JHB0LCBsaXN0KGRmX21lZGlhbl9wdCRzZXVyYXRfY2x1c3RlcnMpLCBtZWRpYW4pCm1lYW4uZGYyIDwtIGFzLmRhdGEuZnJhbWUoYXMudGFibGUobWVhbi5kZjEpKQpuYW1lcyhtZWFuLmRmMikgPC0gYygic2V1cmF0X2NsdXN0ZXJzIiwgInB0X01lZGlhbiIpCnJvd25hbWVzKG1lYW4uZGYyKSA8LSBtZWFuLmRmMiRzZXVyYXRfY2x1c3RlcnMKIyMgdG8gbWFrZSBlYWNoIHZhbHVlIGhhdmUgdGhlIG1lYW4gaW4gdGhlIE9HIGRhdGFmcmFtZQojbWVyZ2UoZGZfbWVkaWFuX3B0LCBtZWFuLmRmMikKIyMgYWRkIHRvIGFubm90YXRpb24gZGF0YWZyYW1lCmNsdXN0ZXJfYW5ubyA8LSBtZXJnZShjbHVzdGVyX2Fubm8sIG1lYW4uZGYyLCBieT0wKQoKIyMgYWRkIHJvd25hbWVzIHRvIGRhdGFmcmFtZQpyb3duYW1lcyhjbHVzdGVyX2Fubm8pIDwtIGNsdXN0ZXJfYW5ubyRSb3cubmFtZXMKIyMgc3Vic2V0IHRvIGhhdmUgb25seSBpbmZvIG9mIGludGVyZXN0CmNsdXN0ZXJfYW5ubyA8LSBjbHVzdGVyX2Fubm9bLGMoMiw0KV0KbmFtZXMoY2x1c3Rlcl9hbm5vKSA8LSBjKCJJZGVudGl0eSIsICJNZWRpYW5fUHNldWRvdGltZV9vZl9DbHVzdGVyIikKYGBgCgojIyMjIFdUIGNlbGxzIGJ5IG1vZHVsZXMgb3ZlciBwdCAoY2VudHJhbCBwYW5lbCkKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEyfQojIyBtYWtlIGFubm90YXRpb24gY29sb3Vycwphbm5vdGF0aW9uX2NvbG91cnMgPC0gbGlzdChJZGVudGl0eSA9IGMoTWFsZT0iIzAxNmMwMCIsIEZlbWFsZT0iI2E1MmIxZSIsIEFzZXh1YWw9ICIjMDA1MmM1IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIE1lZGlhbl9Qc2V1ZG90aW1lX29mX0NsdXN0ZXIgPSBtYWdtYSgxMiwgZGlyZWN0aW9uID0gMSkpCgojIyByZW9yZGVyIHRoZSBsZXZlbHMKIyMgbWFrZSBkZiBvZiBkYXRhCmFnZ19tYXRfZGYgPC0gYXMuZGF0YS5mcmFtZShhZ2dfbWF0KQojIyByZW1vdmUgbGV2ZWxzIGluIG15X2xldmVscyB0aGF0IGFyZSBub3QgcHJlc2VudCBoZXJlIC0gaS5lLiBjbHVzdGVycyB0aGF0IGFyZSBtaXNzaW5nIGJlY2F1c2UgdGhleSBhcmUgbm90IHJlcHJlc2VudGVkIGluIHRoZSAxMFggZGF0YQpteV9sZXZlbHNfMTB4X2RhdGEgPC0gbXlfbGV2ZWxzX3NleFt3aGljaChteV9sZXZlbHNfc2V4ICVpbiUgY29sbmFtZXMoYWdnX21hdF9kZikpXQojIyBzb3J0IHRoZSB2YWx1ZXMKYWdnX21hdF9kZiA8LSBhZ2dfbWF0X2RmWyAsKG1hdGNoKG15X2xldmVsc18xMHhfZGF0YSwgY29sbmFtZXMoYWdnX21hdF9kZikpKV0KCiMjIG9yZGVyIAojY2x1c3Rlcl9hbm5vIDwtIGNsdXN0ZXJfYW5ub1sobWF0Y2gobXlfbGV2ZWxzXzEweF9kYXRhLCByb3duYW1lcyhjbHVzdGVyX2Fubm8pKSksIF0KCiMjIHJlb3JkZXIgY29sdW1ucyAKIyMgZmlyc3QsIG9yZGVyIHRoZSBhbm5vdGF0aW9uCmNsdXN0ZXJfYW5ubyA8LSBjbHVzdGVyX2Fubm9bd2l0aChjbHVzdGVyX2Fubm8sIG9yZGVyKElkZW50aXR5LCBNZWRpYW5fUHNldWRvdGltZV9vZl9DbHVzdGVyKSksXQoKIyMgcmVtb3ZlIHRoZSBOQXMgZnJvbSB0aGlzCmNsdXN0ZXJfYW5ubyA8LSBjbHVzdGVyX2Fubm9bY29tcGxldGUuY2FzZXMoY2x1c3Rlcl9hbm5vKSxdCgphZ2dfbWF0X2RmIDwtIGFnZ19tYXRfZGZbICxtYXRjaChyb3duYW1lcyhjbHVzdGVyX2Fubm8pLCBjb2xuYW1lcyhhZ2dfbWF0X2RmKSldCgojIyBwbG90IGhlYXRtYXAKcGhlYXRtYXA6OnBoZWF0bWFwKGFnZ19tYXRfZGYsIAogICAgICAgICAgICAgICAgICAgc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGNsdXN0ZXJfYW5ubywgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycywgCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDEyKQoKIywgZ2Fwc19jb2wgPSBjKDI4LDI5LDM3KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gMTB9CiNyb3cubmFtZXMoYWdnX21hdCkgPC0gZmFjdG9yKHJvdy5uYW1lcyhhZ2dfbWF0KSwgbGV2ZWxzID0gcm93Lm5hbWVzKGFnZ19tYXQpW21vZHVsZV9kZW5kcm8kb3JkZXJdKQoKIyMgcGxvdCBoZWF0bWFwCiNwaGVhdG1hcDo6cGhlYXRtYXAoYWdnX21hdF9kZiwgCiAgIyAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICMgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBUUlVFLAogICMgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBtb2R1bGVfZGVuZHJvLAogICMgICAgICAgICAgICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICMgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDUsCiAgIyAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gY2x1c3Rlcl9hbm5vLCAKICAjICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMpICsgCiAgIyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpBbGwgQ2VsbHMKClBoZWF0bWFwIHZlcnNpb24KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTJ9CiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfbm9fZ3JvdXAgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4KQoKIyMgbWFrZSBhbiBhbm90YXRpb24KYW5ub19ub19ncm91cCA8LSBkYXRhLmZyYW1lKG1vbm9jbGUub2JqZWN0QGNvbERhdGEkc2V4X1VNQVAsIG1vbm9jbGUub2JqZWN0QGNvbERhdGEkb2xkX3B0X3ZhbHVlcywgcm93Lm5hbWVzID0gcm93bmFtZXMobW9ub2NsZS5vYmplY3RAY29sRGF0YSkpCm5hbWVzKGFubm9fbm9fZ3JvdXApIDwtIGMoInNleCIsICJQc2V1ZG90aW1lIikKCiMjIG1ha2UgYW5ub3RhdGlvbiBjb2xvdXJzCmFubm90YXRpb25fY29sb3VycyA8LSBsaXN0KHNleCA9IGMobWFsZT0iIzAxNmMwMCIsIGZlbWFsZT0iI2E1MmIxZSIsICdwcmUtZGV0JyA9ICIjMDA1MmM1IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFBzZXVkb3RpbWUgPSBtYWdtYSgxMiwgZGlyZWN0aW9uID0gMSkpCgojIyBjaGFuZ2UgdGhlIG9yZGVyIG9mIHRoZSBkYXRhIGZyYW1lCmNvbC5vcmRlciA8LSByb3duYW1lcyhhbm5vX25vX2dyb3VwW3dpdGgoYW5ub19ub19ncm91cCwgb3JkZXIoc2V4LCBQc2V1ZG90aW1lKSksIF0pCmFnZ19tYXRfbm9fZ3JvdXAgPC0gYWdnX21hdF9ub19ncm91cFssY29sLm9yZGVyXQoKIyMgcGxvdApwaGVhdG1hcDo6cGhlYXRtYXAoYWdnX21hdF9ub19ncm91cCwgCiAgICAgICAgICAgICAgICAgICAjc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub19ub19ncm91cCwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycywgCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDEyKQpgYGAKCk5vdyByZWFycmFuZ2UgdGhlIGNvbHMgc28gdGhhdCBpdCBpcyBpbiBhIGJldHRlciBvcmRlcgoKYGBge3J9CiMjIGV4dHJhY3QgZWFjaCBncm91cCBvZiBjZWxscyBpbiB0aGUgY29ycmVjdCBvcmRlciBmb3IgcGxvdHRpbmcKIyMgb3JkZXIgdGhlIGFubm90YXRpb24gZGF0YSBmcmFtZQpvcmRlcmVkX2NlbGxzIDwtIGFubm9fbm9fZ3JvdXBbd2l0aChhbm5vX25vX2dyb3VwLCBvcmRlcihzZXgsIFBzZXVkb3RpbWUpKSwgXQojIyBleHRyYWN0IHRoZSBjZWxscyBpbiB0aGVpciBuZXcgb3JkZXIKZmVtYWxlX29yZGVyZWRfY2VsbHMgPC0gcm93bmFtZXMob3JkZXJlZF9jZWxsc1t3aGljaChvcmRlcmVkX2NlbGxzJHNleCA9PSAiZmVtYWxlIiksIF0pCm1hbGVfb3JkZXJlZF9jZWxscyA8LSByb3duYW1lcyhvcmRlcmVkX2NlbGxzW3doaWNoKG9yZGVyZWRfY2VsbHMkc2V4ID09ICJtYWxlIiksIF0pCnByZV9kZXRfb3JkZXJlZF9jZWxscyA8LSByb3duYW1lcyhvcmRlcmVkX2NlbGxzW3doaWNoKG9yZGVyZWRfY2VsbHMkc2V4ID09ICJwcmUtZGV0IiksIF0pCmNvbC5vcmRlciA8LSBjKHByZV9kZXRfb3JkZXJlZF9jZWxscywgZmVtYWxlX29yZGVyZWRfY2VsbHMsIG1hbGVfb3JkZXJlZF9jZWxscykKIyNjaGVjawojbGVuZ3RoKGNvbC5vcmRlcikKI2RpbShhZ2dfbWF0X25vX2dyb3VwKQoKIyMgcmVvcmRlciB1c2luZyBuZXcgb3JkZXIKYWdnX21hdF9ub19ncm91cCA8LSBhZ2dfbWF0X25vX2dyb3VwWyxjb2wub3JkZXJdCgojIyByZW9yZGVyIHRoZSByb3dzCiMjIGRlZmluZSB0aGUgb3JkZXIgdmlzdWFsbHkgYW5kIHVzaW5nIHRoZSBjbHVzdGVycyBvcmlnaW5hbGx5IHByb2R1Y2VkCnJvdy5vcmRlciA8LSBjKCI1IiwgIjQiLCAiMTMiLCAiMTEiLCAiNiIsICIyIiwgIjciLCAiMyIsICI4IiwgIjE3IiwgIjkiLCAiMTYiLCAiMTQiLCAiMTIiLCAiMTUiLCAiMSIsICIxMCIpCgojIyByZW9yZGVyIHVzaW5nIG5ldyBvcmRlcgphZ2dfbWF0X25vX2dyb3VwIDwtIGFnZ19tYXRfbm9fZ3JvdXBbcm93Lm9yZGVyLCBdCgojIyBhZGQgbW9kdWxlIGFuZCB0aGUgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3cKIyMgY2hhbmdlIG5hbWVzIGZvciByb3cgbmFtZXMgdG8gaW5jbHVkZSAibW9kdWxlICIgYXQgdGhlIGJlZ2luaW5nIG9mIHRoZW0KbGFiZWxzLnJvdyA8LSBzdHJpbmdyOjpzdHJfYygiTW9kdWxlICIsIHJvdy5uYW1lcyhhZ2dfbWF0X25vX2dyb3VwKSkKIyMgcmVvcmRlciBmcmVxdWVuY3kgc28gdGhhdCBpdCBpcyBtYXRjaGluZyBvdXIgbWF0cml4CmdlbmVzX3Blcl9tb2R1bGVfb3JkZXJlZCA8LSBnZW5lc19wZXJfbW9kdWxlW21hdGNoKHJvdy5uYW1lcyhhZ2dfbWF0X25vX2dyb3VwKSwgZ2VuZXNfcGVyX21vZHVsZSRWYXIxKSwgXQojIyBhZGQgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3duYW1lcyBmb3IgdGhlIG1vZHVsZQpmb3IoaSBpbiBzZXFfYWxvbmcoZ2VuZXNfcGVyX21vZHVsZV9vcmRlcmVkJEZyZXEpKXsKICBsYWJlbHMucm93W2ldIDwtIHN0cmluZ3I6OnN0cl9jKGxhYmVscy5yb3dbaV0sIiAobiA9ICIgLGdlbmVzX3Blcl9tb2R1bGVfb3JkZXJlZCRGcmVxW2ldLCAiKSIpCn0KCiMjIHBsb3QKaGVhdG1hcF9tYWluIDwtIHBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X25vX2dyb3VwLCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBsYWJlbHNfcm93ID0gbGFiZWxzLnJvdywKICAgICAgICAgICAgICAgICAgIGdhcHNfY29sID0gYyhsZW5ndGgocHJlX2RldF9vcmRlcmVkX2NlbGxzKSwgbGVuZ3RoKHByZV9kZXRfb3JkZXJlZF9jZWxscykgKyBsZW5ndGgoZmVtYWxlX29yZGVyZWRfY2VsbHMpKSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub19ub19ncm91cCwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycywgCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDEyKQoKaGVhdG1hcF9tYWluCmBgYAoKIyMjIFBsb3Qgc3BlY2lmaWMgZ2VuZXMgb2YgaW50ZXJlc3QKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTB9CiMjIGxhbmRtYXJrIGdlbmVzIChnZW5lcyBvZiBpbnRlcmVzdCkKIyBBUDJHIC0gUEJBTktBLTE0Mzc1MDAKIyBBUDIgLSBQQkFOS0EtMDkwOTYwMCAtIGZyb20gcG9yYW4gcGFwZXIKIyBBUDJHLTIgLSBQQkFOS0EtMTAzNDMwMCAKI2xpc3Rfb2ZfbXV0YW50X2dlbmVzIDwtIGMoIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIikKCmxpc3Rfb2ZfZ2VuZXNfb2ZfaW50ZXJlc3QgPC0gYygiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTE0NTQ4MDAiLCAiUEJBTktBLTE0Mzc1MDAiLCAiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiKQpuYW1lc19vZl9nZW5lc19vZl9pbnRlcmVzdCA8LSBjKCJHQ1NLTy0yIiwgIkdDU0tPLTEwIiwgIkdDU0tPLTE5IiwgIkdDU0tPLTMiLCAiR0NTS08tMTMiLCAiR0NTS08tMjgiLCAiR0NTS08tb29tIiwgIkdDU0tPLTE3IiwgIkdDU0tPLTIwIiwgIkdDU0tPLTI5IiwgIkdDU0tPLTIxIiwgIkFQMi1HIiwgIkNDUDIiLCAiTUcxIikKIyNtYWtlIGRmIGZvciBnZW5lcyBvZiBpbnRlcmVzdApnZW5lc19vZl9pbnRlcmVzdCA8LSBkYXRhLmZyYW1lKGdlbmUgPSBsaXN0X29mX2dlbmVzX29mX2ludGVyZXN0LCBncm91cCA9IGMoMTpsZW5ndGgobGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCkpLCBuYW1lID0gbmFtZXNfb2ZfZ2VuZXNfb2ZfaW50ZXJlc3QpCiMjIHJlb3JkZXIKI2dlbmVzX29mX2ludGVyZXN0IDwtIGdlbmVzX29mX2ludGVyZXN0W21hdGNoKGMoIkFQMi1HIiwgIkNDUDIiLCAiR0NTS08tMjEiLCAiR0NTS08tMTciLCAiR0NTS08tMiIsICJNRzEiLCAiR0NTS08tMjAiLCAiR0NTS08tMyIsICJHQ1NLTy1vb20iLCAiR0NTS08tMjkiLCAiR0NTS08tMTAiLCAiR0NTS08tMjgiLCAiR0NTS08tMTkiLCAiR0NTS08tMTMiKSwgZ2VuZXNfb2ZfaW50ZXJlc3QkbmFtZSksIF0KCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdCwgZ2VuZXNfb2ZfaW50ZXJlc3RbLDE6Ml0pCgojIyByZW9yZGVyIHVzaW5nIG5ldyBvcmRlcgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbLGNvbC5vcmRlcl0KCiMjIHBsb3QKaGVhdG1hcF9wbG90IDwtIHBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGxhYmVsc19yb3cgPSBhcy5jaGFyYWN0ZXIoZ2VuZXNfb2ZfaW50ZXJlc3RbLDNdKSwKICAgICAgICAgICAgICAgICAgIGdhcHNfY29sID0gYyhsZW5ndGgocHJlX2RldF9vcmRlcmVkX2NlbGxzKSwgbGVuZ3RoKHByZV9kZXRfb3JkZXJlZF9jZWxscykgKyBsZW5ndGgoZmVtYWxlX29yZGVyZWRfY2VsbHMpKSwKICAgICAgICAgICAgICAgICAgICNnYXBzX3JvdyA9IGMoMSwgNiksCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDIsCiAgICAgICAgICAgICAgICAgICAjIyB0cnlpbmcgdG8gZml4IGxlZ2VuZCBpc3N1ZSBoZXJlCiAgICAgICAgICAgICAgICAgICAjZm9udHNpemVfcm93ID0gMTAsCiAgICAgICAgICAgICAgICAgICAjZm9udHNpemVfY29sID0gMywKICAgICAgICAgICAgICAgICAgICNjZWxsaGVpZ2h0PTMsIAogICAgICAgICAgICAgICAgICAgI2NlbGx3aWR0aCA9IDMsCiAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sID0gYW5ub19ub19ncm91cCwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycwogICAgICAgICAgICAgICAgICAgKQoKaGVhdG1hcF9wbG90CmBgYAoKU2lkZSBwbG90cwoKY29uc3RydWN0IG5ldyBkYXRhZnJhbWVzIGZvciB0aGUgY2VsbHMgZnJvbSBtdXRhbnRzIGZvciBlYWNoIHNleApgYGB7cn0KIyMgVGhlIG9yaWdpbmFsIG9iamVjdCBjb250YWlucyBhbGwgY2VsbHMsIHdlIGp1c3Qgd2FudCB3aWxkLXR5cGUgc28gbGV0J3Mgc3Vic2V0IG91dCBnZW5lX21vZHVsZV9kZiBhbmQgY2VsbF9ncm91cF9kZiBhY2NvcmRpbmdseQoKIyMgbWFsZQojIyBzdWJzZXQgb3V0IG9ubHkgbWFsZSBhbmQgcHJlIGRldGVybWluYXRpb24gY2VsbHMKbWFsZV9jZWxscyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGF0X3NleCA9PSAibWFsZSIpLCBdCiMjIHRha2UgZm9yd2FyZCBvbmx5IHNtYXJ0LXNlcTIKbWFsZV9jZWxscyA8LSBtYWxlX2NlbGxzW3doaWNoKG1hbGVfY2VsbHMkZXhwZXJpbWVudCA9PSAibXV0YW50cyIpLCBdCiMjIGdldCBjZWxsIG5hbWVzCm1hbGVfY2VsbHMgPC0gcm93bmFtZXMobWFsZV9jZWxscykKIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gY29udGFpbiBjZWxscyBvZiBpbnRlcmVzdCAgCm1hbGUuc2V1cmF0Lm9iamVjdCA8LSBTdWJzZXREYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscyA9IG1hbGVfY2VsbHMpCiMjIG1ha2UgbmV3IGNvdW50cyBhbmQgcGhlbm86CmRhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShtYWxlLnNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUobWFsZS5zZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkKIyMga2VlcCBvbmx5IHRoZSBjb2x1bW5zIHRoYXQgYXJlIHJlbGV2YW50CiNwRGF0YSA8LSBwZCAlPiUgc2VsZWN0KG9yaWcuaWRlbnQsIG5Db3VudF9STkEsIG5GZWF0dXJlX1JOQSkKZkRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3cubmFtZXMoZGF0YSksIHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhkYXRhKSkKIyMgQ29uc3RydWN0IG1vbm9jbGUgY2RzCm1hbGUubW9ub2NsZS5vYmplY3QgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCiMjIHByZXByb2Nlc3MKbWFsZS5tb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKG1hbGUubW9ub2NsZS5vYmplY3QsIG51bV9kaW0gPSA1MCwgbm9ybV9tZXRob2QgPSAibm9uZSIpICAKIyMgbWFrZSBhIG5ldyBkYXRhZnJhbWUgZm9yIGNlbGwgZ3JvdXBzIC0gaXQgaXMgY3J1Y2lhbCB0byByZWZhY3RvciBvdGhlcndpc2UgYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbiB0aGlua3MgaXQncyBvdXQgb2YgYm91bmRzICAKI21hbGVfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGw9YXMuY2hhcmFjdGVyKGZhY3RvcihtYWxlX2NlbGxfZ3JvdXBfZGYkY2VsbF9pZCkpLCBjZWxsX2dyb3VwPWZhY3RvcihtYWxlX2NlbGxfZ3JvdXBfZGYkcHRfYmluKSkgIAojIyBhZ2dyZWdhdGUgZXhwcmVzc2lvbgptYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtYWxlLm1vbm9jbGUub2JqZWN0LCBnZW5lX21vZHVsZV9kZl9zZXgsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKCiMjIGZlbWFsZQojIyBzdWJzZXQgb3V0IG9ubHkgbWFsZSBhbmQgcHJlIGRldGVybWluYXRpb24gY2VsbHMKZmVtYWxlX2NlbGxzIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkYXRfc2V4ID09ICJmZW1hbGUiKSwgXQojIyB0YWtlIGZvcndhcmQgb25seSB3aWxkLXR5cGUKZmVtYWxlX2NlbGxzIDwtIGZlbWFsZV9jZWxsc1t3aGljaChmZW1hbGVfY2VsbHMkZXhwZXJpbWVudCA9PSAibXV0YW50cyIpLCBdCiMjIGdldCBjZWxsIG5hbWVzCmZlbWFsZV9jZWxscyA8LSByb3duYW1lcyhmZW1hbGVfY2VsbHMpCiMjIHN1YnNldCBvdXIgY2VsbCBncm91cCBkZiB0byBrZWVwIG9ubHkgdGhlc2UgY2VsbHMKI2ZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmW3doaWNoKGZlbWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQgJWluJSBmZW1hbGVfY2VsbHMpLF0KIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gY29udGFpbiBjZWxscyBvZiBpbnRlcmVzdCAgCmZlbWFsZS5zZXVyYXQub2JqZWN0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gZmVtYWxlX2NlbGxzKQojIyBtYWtlIG5ldyBjb3VudHMgYW5kIHBoZW5vOgpkYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEoZmVtYWxlLnNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUoZmVtYWxlLnNldXJhdC5vYmplY3RAbWV0YS5kYXRhKQojIyBrZWVwIG9ubHkgdGhlIGNvbHVtbnMgdGhhdCBhcmUgcmVsZXZhbnQKI3BEYXRhIDwtIHBkICU+JSBzZWxlY3Qob3JpZy5pZGVudCwgbkNvdW50X1JOQSwgbkZlYXR1cmVfUk5BKQpmRGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IHJvdy5uYW1lcyhkYXRhKSwgcm93Lm5hbWVzID0gcm93Lm5hbWVzKGRhdGEpKQojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKZmVtYWxlLm1vbm9jbGUub2JqZWN0IDwtIG5ld19jZWxsX2RhdGFfc2V0KGV4cHJlc3Npb25fZGF0YSA9IGRhdGEsIGNlbGxfbWV0YWRhdGEgPSBwZCwgZ2VuZV9tZXRhZGF0YSA9IGZEYXRhKQojIyBwcmVwcm9jZXNzCmZlbWFsZS5tb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKGZlbWFsZS5tb25vY2xlLm9iamVjdCwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikgIAojIyBtYWtlIGEgbmV3IGRhdGFmcmFtZSBmb3IgY2VsbCBncm91cHMgLSBpdCBpcyBjcnVjaWFsIHRvIHJlZmFjdG9yIG90aGVyd2lzZSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uIHRoaW5rcyBpdCdzIG91dCBvZiBib3VuZHMgIAojZmVtYWxlX2NlbGxfZ3JvdXBfZGYgPC0gZGF0YS5mcmFtZShjZWxsPWFzLmNoYXJhY3RlcihmYWN0b3IoZmVtYWxlX2NlbGxfZ3JvdXBfZGYkY2VsbF9pZCkpLCBjZWxsX2dyb3VwPWZhY3RvcihmZW1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4pKSAgCiMjIGFnZ3JlZ2F0ZSBleHByZXNzaW9uCmZlbWFsZV9hZ2dfbWF0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24oZmVtYWxlLm1vbm9jbGUub2JqZWN0LCBnZW5lX21vZHVsZV9kZl9zZXgsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKYGBgCgptYWxlCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTJ9CiMgbWFsZV9hZ2dfbWF0CiMjIHJlb3JkZXIgdXNpbmcgbmV3IG9yZGVyCm1hbGVfYWdnX21hdCA8LSBtYWxlX2FnZ19tYXRbcm93Lm9yZGVyLCBdCgojIyBtYWtlIGFuIGFub3RhdGlvbgphbm5vX21hbGUgPC0gZGF0YS5mcmFtZShtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEkYXRfc2V4LCBtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEkb2xkX3B0X3ZhbHVlcywgZ2Vub3R5cGUgPSBtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEkaWRlbnRpdHlfdXBkYXRlZCwgcm93Lm5hbWVzID0gcm93bmFtZXMobWFsZS5tb25vY2xlLm9iamVjdEBjb2xEYXRhKSkKbmFtZXMoYW5ub19tYWxlKSA8LSBjKCJzZXgiLCAiUHNldWRvdGltZSIsICJnZW5vdHlwZSIpCgojIyBtYWtlIGFubm90YXRpb24gY29sb3Vycwphbm5vdGF0aW9uX2NvbG91cnMgPC0gbGlzdChzZXggPSBjKG1hbGU9IiMwMTZjMDAiLCBmZW1hbGU9IiNhNTJiMWUiLCAncHJlLWRldCcgPSAiIzAwNTJjNSIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBQc2V1ZG90aW1lID0gbWFnbWEoMTIsIGRpcmVjdGlvbiA9IDEpKQoKIyMgY2hhbmdlIHRoZSBvcmRlciBvZiB0aGUgZGF0YSBmcmFtZQpjb2wub3JkZXIubWFsZSA8LSByb3duYW1lcyhhbm5vX21hbGVbd2l0aChhbm5vX21hbGUsIG9yZGVyKGdlbm90eXBlLCBQc2V1ZG90aW1lKSksIF0pCm1hbGVfYWdnX21hdCA8LSBtYWxlX2FnZ19tYXRbLGNvbC5vcmRlci5tYWxlXQoKIyMgcGxvdApoZWF0bWFwX21hbGUgPC0gcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICAjc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fbWFsZSwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycywgCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDEyKQoKaGVhdG1hcF9tYWxlCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMn0KIyBmZW1hbGVfYWdnX21hdAojIyByZW9yZGVyIHVzaW5nIG5ldyBvcmRlcgpmZW1hbGVfYWdnX21hdCA8LSBmZW1hbGVfYWdnX21hdFtyb3cub3JkZXIsIF0KCiMjIG1ha2UgYW4gYW5vdGF0aW9uCmFubm9fZmVtYWxlIDwtIGRhdGEuZnJhbWUoZmVtYWxlLm1vbm9jbGUub2JqZWN0QGNvbERhdGEkYXRfc2V4LCBmZW1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSRvbGRfcHRfdmFsdWVzLCBnZW5vdHlwZSA9IGZlbWFsZS5tb25vY2xlLm9iamVjdEBjb2xEYXRhJGlkZW50aXR5X3VwZGF0ZWQsIHJvdy5uYW1lcyA9IHJvd25hbWVzKGZlbWFsZS5tb25vY2xlLm9iamVjdEBjb2xEYXRhKSkKbmFtZXMoYW5ub19mZW1hbGUpIDwtIGMoInNleCIsICJQc2V1ZG90aW1lIiwgImdlbm90eXBlIikKCiMjIG1ha2UgYW5ub3RhdGlvbiBjb2xvdXJzCmFubm90YXRpb25fY29sb3VycyA8LSBsaXN0KHNleCA9IGMobWFsZT0iIzAxNmMwMCIsIGZlbWFsZT0iI2E1MmIxZSIsICdwcmUtZGV0JyA9ICIjMDA1MmM1IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFBzZXVkb3RpbWUgPSBtYWdtYSgxMiwgZGlyZWN0aW9uID0gMSkpCgojIyBjaGFuZ2UgdGhlIG9yZGVyIG9mIHRoZSBkYXRhIGZyYW1lCmNvbC5vcmRlci5mZW1hbGUgPC0gcm93bmFtZXMoYW5ub19mZW1hbGVbd2l0aChhbm5vX2ZlbWFsZSwgb3JkZXIoZ2Vub3R5cGUsIFBzZXVkb3RpbWUpKSwgXSkKZmVtYWxlX2FnZ19tYXQgPC0gZmVtYWxlX2FnZ19tYXRbLGNvbC5vcmRlci5mZW1hbGVdCgojIyBwbG90CmhlYXRtYXBfZmVtYWxlIDwtIHBoZWF0bWFwOjpwaGVhdG1hcChmZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICAjc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhbm5vX2ZlbWFsZSwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycywgCiAgICAgICAgICAgICAgICAgICBjdXRyZWVfcm93cyA9IDEyKQoKaGVhdG1hcF9mZW1hbGUKCiMjIHNhdmUgYSBwaGVhdG1hcDogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDMwNTE1MjUvaG93LXRvLWRyYXctcGhlYXRtYXAtcGxvdC10by1zY3JlZW4tYW5kLWFsc28tc2F2ZS10by1maWxlCmBgYAoKc2lkZSBwbG90cyB3aXRoIGdyb3VwcyBvZiBtdXRhbnQgY2VsbHMKCmZlbWFsZQpgYGB7cn0KIyMgbWFrZSBhIG5ldyBncm91cGluZyBmb3IgY2VsbHMgYmFzZWQgb24gdGhlaXIgaWRlbnRpdHkKbXV0YW50X2dyb3VwX2ZlbWFsZSA8LSBkYXRhLmZyYW1lKGNlbGwgPSByb3duYW1lcyhmZW1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSksIGNlbGxfZ3JvdXAgPSBmZW1hbGUubW9ub2NsZS5vYmplY3RAY29sRGF0YSRpZGVudGl0eV91cGRhdGVkKQoKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KZmVtYWxlX2FnZ19tYXRfZ3JvdXBlZCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKGZlbWFsZS5tb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBtdXRhbnRfZ3JvdXBfZmVtYWxlLCBleGNsdWRlLm5hID0gRkFMU0UpCgojIyByZW9yZGVyIHVzaW5nIG5ldyBvcmRlcgpmZW1hbGVfYWdnX21hdF9ncm91cGVkIDwtIGZlbWFsZV9hZ2dfbWF0X2dyb3VwZWRbcm93Lm9yZGVyLCBdCgojIyBwbG90CnBoZWF0bWFwOjpwaGVhdG1hcChmZW1hbGVfYWdnX21hdF9ncm91cGVkLCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIHNob3dfY29sbmFtZXMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgbGVnZW5kID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgI2Fubm90YXRpb25fY29sID0gYW5ub19mZW1hbGUsIAogICAgICAgICAgICAgICAgICAgI2Fubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLCAKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMTIpCgoKYGBgCgptYWxlCmBgYHtyfQoKYGBgCgptb2R1bGUgMTIgaW5zcGVjdGlvbgoKYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9CiMjIG1ha2UgYSBkZiBmb3IgbW9kdWxlIDEyIGdlbmVzCm1vZHVsZS4xMi5nZW5lcyA8LSBnZW5lX21vZHVsZV9kZl9zZXhbZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSA9PSAxMiwgXSRpZAptb2R1bGUuMTIuZ2VuZXMgPC0gZGF0YS5mcmFtZShpZCA9IG1vZHVsZS4xMi5nZW5lcywgZ3JvdXAgPSBtb2R1bGUuMTIuZ2VuZXMpCgojIyBwcmVwYXJlIGN1c3RvbSBkYXRhZnJhbWUgZm9yIGFsbCBjZWxscyBieSBtb2R1bGVzOgphZ2dfbWF0X21vZHVsZV8xMiA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBtb2R1bGUuMTIuZ2VuZXMpCgojIyBtYWtlIGFuIGFub3RhdGlvbgphbm5vX25vX2dyb3VwIDwtIGRhdGEuZnJhbWUobW9ub2NsZS5vYmplY3RAY29sRGF0YSRzZXhfVU1BUCwgbW9ub2NsZS5vYmplY3RAY29sRGF0YSRvbGRfcHRfdmFsdWVzLCByb3cubmFtZXMgPSByb3duYW1lcyhtb25vY2xlLm9iamVjdEBjb2xEYXRhKSkKbmFtZXMoYW5ub19ub19ncm91cCkgPC0gYygic2V4IiwgIlBzZXVkb3RpbWUiKQoKIyMgbWFrZSBhbm5vdGF0aW9uIGNvbG91cnMKYW5ub3RhdGlvbl9jb2xvdXJzIDwtIGxpc3Qoc2V4ID0gYyhtYWxlPSIjMDE2YzAwIiwgZmVtYWxlPSIjYTUyYjFlIiwgJ3ByZS1kZXQnID0gIiMwMDUyYzUiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgUHNldWRvdGltZSA9IG1hZ21hKDEyLCBkaXJlY3Rpb24gPSAxKSkKCiMjIGNoYW5nZSB0aGUgb3JkZXIgb2YgdGhlIGRhdGEgZnJhbWUKY29sLm9yZGVyIDwtIGMocHJlX2RldF9vcmRlcmVkX2NlbGxzLCBmZW1hbGVfb3JkZXJlZF9jZWxscywgbWFsZV9vcmRlcmVkX2NlbGxzKQphZ2dfbWF0X21vZHVsZV8xMiA8LSBhZ2dfbWF0X21vZHVsZV8xMlssY29sLm9yZGVyXQoKIyMgcGxvdApwaGVhdG1hcDo6cGhlYXRtYXAoYWdnX21hdF9tb2R1bGVfMTIsIAogICAgICAgICAgICAgICAgICAgI3NjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBzaG93X2NvbG5hbWVzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGFubm9fbm9fZ3JvdXAsIAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2xvcnMgPSBhbm5vdGF0aW9uX2NvbG91cnMsCiAgICAgICAgICAgICAgICAgICBmb250c2l6ZV9yb3cgPSA3LAogICAgICAgICAgICAgICAgICAgY3V0cmVlX3Jvd3MgPSAxMikKYGBgCnNhdmUgcGxvdApgYGB7cn0KaGVhdG1hcF9tb2R1bGVfMTIgPC0gcGhlYXRtYXA6OnBoZWF0bWFwKGFnZ19tYXRfbW9kdWxlXzEyLCAKICAgICAgICAgICAgICAgICAgICNzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhbm5vX25vX2dyb3VwLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLAogICAgICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gNywKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMTIpCmBgYAoKQVAyIEV4cHJlc3Npb24KCmBgYHtyfQojIyByZWFkaW5nIHRhYmxlIG9mIEFQMiBnZW5lcwphcDJfZ2VuZXNfdGFibGUgPC0gcmVhZC5kZWxpbShmaWxlID0gIn4vZGF0YS9BUDJfZ2VuZXNfdGFibGUudHh0IiwgaGVhZGVyID0gVFJVRSwgc2VwID0iXHQiKQoKIyMgZXh0cmFjdCBsaXN0IG9mIGdlbmVzCmFwMl9nZW5lc19saXN0IDwtIGRwbHlyOjpwdWxsKGFwMl9nZW5lc190YWJsZSwgR2VuZS5JRCkKYXAyX2dlbmVzX2xpc3QgPC0gZ3N1YigiXyIsICItIiwgYXAyX2dlbmVzX2xpc3QpCgojIyBtYWtlIGEgZGYgZm9yIGdlbmVzCmFwMl9nZW5lc19saXN0IDwtIGRhdGEuZnJhbWUoaWQgPSBhcDJfZ2VuZXNfbGlzdCwgZ3JvdXAgPSBhcDJfZ2VuZXNfbGlzdCkKCiMjIHByZXBhcmUgY3VzdG9tIGRhdGFmcmFtZSBmb3IgYWxsIGNlbGxzIGJ5IG1vZHVsZXM6CmFnZ19tYXRfYXAycyA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBhcDJfZ2VuZXNfbGlzdCkKCiMjIGNoYW5nZSB0aGUgb3JkZXIgb2YgdGhlIGRhdGEgZnJhbWUKY29sLm9yZGVyIDwtIGMocHJlX2RldF9vcmRlcmVkX2NlbGxzLCBmZW1hbGVfb3JkZXJlZF9jZWxscywgbWFsZV9vcmRlcmVkX2NlbGxzKQphZ2dfbWF0X2FwMnMgPC0gYWdnX21hdF9hcDJzWyxjb2wub3JkZXJdCgojIyBwbG90CnBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2FwMnMsIAogICAgICAgICAgICAgICAgICAgI3NjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyaW5nX21ldGhvZD0iY29tcGxldGUiLAogICAgICAgICAgICAgICAgICAgc2hvd19jb2xuYW1lcyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgYW5ub3RhdGlvbl9jb2wgPSBhbm5vX25vX2dyb3VwLCAKICAgICAgICAgICAgICAgICAgIGFubm90YXRpb25fY29sb3JzID0gYW5ub3RhdGlvbl9jb2xvdXJzLAogICAgICAgICAgICAgICAgICAgZm9udHNpemVfcm93ID0gNywKICAgICAgICAgICAgICAgICAgIGN1dHJlZV9yb3dzID0gMykKYGBgCgoKIyMjIE1vZHVsZSBBbmFseXNpcyAKClJlYWQgaW4gS2FzaWEncyBtb2R1bGVzOgpgYGB7cn0KIyMgcmVhZCBpbiBrYXNpYSBtb2R1bGVzOgprYXNpYV9jbHVzdGVycyA8LSByZWFkLmNzdihmaWxlID0gIn4vZGF0YS9Nb2R1bGVzX0NsdXN0ZXJzX1BoZW5vdHlwZXMuY3N2IiwgaGVhZGVyID0gVFJVRSkKCiMjIGNoYW5nZSBfIHRvIC06Cmthc2lhX2NsdXN0ZXJzJG5ldy5nZW5lLklEIDwtIGdzdWIoIl8iLCAiLSIsIGthc2lhX2NsdXN0ZXJzJG5ldy5nZW5lLklEKQoKIyMgZmlsdGVyIG91dCBnZW5lcyBub3QgaW4gbW9kdWxlcyBnZW5lX21vZHVsZV9kZl9zZXg6Cmthc2lhX2NsdXN0ZXJzX2ZpbHRlcmVkIDwtIGthc2lhX2NsdXN0ZXJzW3doaWNoKGthc2lhX2NsdXN0ZXJzJG5ldy5nZW5lLklEICVpbiUgZ2VuZV9tb2R1bGVfZGZfc2V4JGlkKSwgXQoKIyMgcmVuYW1lIG5ldyBnZW5lIGlkCm5hbWVzKGthc2lhX2NsdXN0ZXJzX2ZpbHRlcmVkKVsyXSA8LSAiaWQiCgojIyBtZXJnZSB0b2dldGhlcgptb2R1bGVzX21lcmdlZF9kZiA8LSBtZXJnZShrYXNpYV9jbHVzdGVyc19maWx0ZXJlZCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBieSA9ICJpZCIpCgojIyBsb29rIGF0IHRoZSBlbnJpY2htZW50IHdpdGggYSBkb3RwbG90Ogpkb3RfcGxvdF9kZl9wYyA8LSAoYXMuZGF0YS5mcmFtZS5tYXRyaXgocHJvcC50YWJsZSh0YWJsZShtb2R1bGVzX21lcmdlZF9kZiRLYXNpYS5DbHVzdGVyLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfY29tYmluZWQpLCBtYXJnaW4gPSAyKSkgKiAxMDApCmBgYAoKCgoKCgoKCgpOT1QgVVNFRApjb21wbGV4IGhlYXRtYXAgdmVyc2lvbgoKYGBge3J9CiMjIG1ha2UgaW50byBtYXRyaXggdG8gcGxvdApjb2wub3JkZXIgPC0gYWdnX21hdF9hbGxfY2VsbHNfbWF0cml4IDwtIGFzLm1hdHJpeChhZ2dfbWF0X2FsbF9jZWxscykKYGBgCgptYWtlIGFubm90YXRpb24KYGBge3J9CiMjIGV4dHJhY3QgcHNldWRvdGltZSB2YWx1ZXM6CnB0X3ZhbHVlcyA8LSBhcy5kYXRhLmZyYW1lKHBzZXVkb3RpbWUobW9ub2NsZS5vYmplY3QsIHJlZHVjdGlvbl9tZXRob2QgPSAiVU1BUCIpKQpuYW1lcyhwdF92YWx1ZXMpIDwtICJtb25vY2xlX3B0X3NleF93dCIKdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXggPC0gQWRkTWV0YURhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIHB0X3ZhbHVlcykKCiMjIHNhdmUgcHQgdmFsdWVzCndyaXRlLmNzdihwdF92YWx1ZXMsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9wdF92YWx1ZXNfc2V4X29ubHkuY3N2IikKYGBgCgpgYGB7cn0KbGlicmFyeShjaXJjbGl6ZSkKIyMgbWFrZSB0aGUgYW5ub3RhdGlvbiBkZgojIyBnZXQgbWV0YSBkYXRhIGZyb20gc2V1cmF0IG9iamVjdCBhbmQgdGhlbiBzdWJzZXQgcm93cyBvdXQgdGhhdCBhcmUgd3QKZGZfYW5ubyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2gocm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhKSAlaW4lIGNvbG5hbWVzKGFnZ19tYXRfYWxsX2NlbGxzX21hdHJpeCkpLCBdCiMjIGdldCBvbmx5IGNvbHVtbnMgb2YgaW50ZXJlc3Q6CmRmX2Fubm8gPC0gZGZfYW5ub1sgLGMoInNleCIsICJtb25vY2xlX3B0X3NleF93dCIpLCBkcm9wID0gRkFMU0UgXQoKIyMgb3JkZXIgYW5ub3RhdGlvbgpkZl9hbm5vIDwtIGRmX2Fubm9bd2l0aChkZl9hbm5vLCBvcmRlcihzZXgsIG1vbm9jbGVfcHRfc2V4X3d0KSksXQoKIyMgb3JkZXIgY29scyBpbiB0aGUgbWF0cml4CmFnZ19tYXRfYWxsX2NlbGxzX21hdHJpeCA8LSBhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXhbICxtYXRjaChjb2xuYW1lcyhhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgpLCByb3duYW1lcyhkZl9hbm5vKSldCgojIyBtYWtlIGFubm90YXRpb24KaGVhdG1hcF9hbm5vdGF0aW9uIDwtIEhlYXRtYXBBbm5vdGF0aW9uKGRmID0gY2x1c3Rlcl9hbm5vLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3Qoc2V4ID0gYyhtYWxlPSIjMDE2YzAwIiwgZmVtYWxlPSIjYTUyYjFlIiwgYHByZS1kZXRgID0gIiMwMDUyYzUiKSwgbW9ub2NsZV9wdF9zZXhfd3QgPSBjb2xvclJhbXAyKGMoMTo3MCksIGluZmVybm8oNzApKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKCmhlYXRtYXBfYW5ub3RhdGlvbiA8LSBIZWF0bWFwQW5ub3RhdGlvbihzZXggPSBkZl9hbm5vJHNleCwgcHQgPSBkZl9hbm5vJG1vbm9jbGVfcHRfc2V4X3d0KQpgYGAKCnBsb3QKYGBge3J9CiMjIG1ha2UgaGVhdG1hcAptb2R1bGVzX2hlYXRtYXAgPC0gSGVhdG1hcChhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgY29sdW1uX2xhYmVscyA9IHJlcCgiIiwgbmNvbChhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgpKSwKICAgICAgICAjcm93X29yZGVyID0gbW9kdWxlX2RlbmRybyRvcmRlciwKICAgICAgICBjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zID0gIndhcmQuRDIiLAogICAgICAgIGJvdHRvbV9hbm5vdGF0aW9uID0gaGVhdG1hcF9hbm5vdGF0aW9uLAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPQogICJSZFlsQnUiKSkpKDEwMCksIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMgcHJpbnQKZHJhdyhtb2R1bGVzX2hlYXRtYXAsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CiMjIGV4dHJhY3QgY291bnRzIGZyb20gMTB4IG9iamVjdAptYXRyaXhfdGVueF9jb3VudHMgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShwYl9zZXhfZmlsdGVyZWQsIGFzc2F5ID0gIlJOQSIpKQojbmsucmF3LmRhdGEgPC0gYXMubWF0cml4KEdldEFzc2F5RGF0YShwYl9zZXhfZmlsdGVyZWQsIHNsb3QgPSAiY291bnRzIilbLCBXaGljaENlbGxzKHBibWMsIGlkZW50ID0gIk5LIildKQoKIyMgY2hlY2sgaXQgaXMgdGhlIHNhbWUgYXMgdGhlIG1lcmdlZCBvYmplY3QgUk5BIHNsb3QKCiMjIGNoZWNrIGl0IGlzIHRoZSBzYW1lIGFzIHRoZSBtb25vY2xlIG9iamVjdAptYXRyaXhfdGVueF9jb3VudHNfbW9ub2NsZSA8LSBhcy5tYXRyaXgoYXMuZGF0YS5mcmFtZSgobW9ub2NsZS5vYmplY3RAYXNzYXlzKSkpCmBgYAoKYGBge3J9CiMjIG1ha2UgaGVhdG1hcAptb2R1bGVzX2hlYXRtYXAgPC0gSGVhdG1hcChtYXRyaXhfdGVueF9jb3VudHMsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fbGFiZWxzID0gcmVwKCIiLCBuY29sKG1hdHJpeF90ZW54X2NvdW50cykpLAogICAgICAgICNyb3dfb3JkZXIgPSBtb2R1bGVfZGVuZHJvJG9yZGVyLAogICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnMgPSAid2FyZC5EMiIsCiAgICAgICAgI2JvdHRvbV9hbm5vdGF0aW9uID0gaGVhdG1hcF9hbm5vdGF0aW9uLAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPQogICJSZFlsQnUiKSkpKDEwMCksIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMgcHJpbnQKZHJhdyhtb2R1bGVzX2hlYXRtYXAsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKIyMjIyBwbG90IGFzIGEgZnVuY3Rpb24gb2YgcHNldWRvdGltZQoKTm93LCB3ZSB3aWxsIGludGVncmF0ZSB0aGUgYnJhbmNoIGRhdGEgd2UgcHJvZHVjZWQgdXNpbmcgc2xpbmdzaG90IGFuZCB0aGUgcHNldWRvdGltZSB2YWx1ZXMgdG8gcGxvdCB0aGlzIGhlYXRtYXAuIAoKTW9ub2NsZTMgaGFzIGEgaGFuZHkgZnVuY3Rpb24gdGhhdCBhbGxvd3MgdXMgdG8gYWdncmVnYXRlIGV4cHJlc3Npb24gb2YgZ3JvdXBzIG9mIGNlbGxzIGNhbGxlZCBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uLiAKClRoZSBjb2RlIGZvciB0aGlzIGlzIGxvY2F0ZWQgaGVyZTogaHR0cHM6Ly9naXRodWIuY29tL2NvbGUtdHJhcG5lbGwtbGFiL21vbm9jbGUzL2Jsb2IvMWEwMjI3NDIwOWM3NjVmZTdhNjBmNTMzYTMxYjFkYTNkYWNmNjc4NS9SL2NsdXN0ZXJfZ2VuZXMuUiAKCkRlZmluZSB0aGUgZ3JvdXBzIG9mIGNlbGxzCmBgYHtyfQojIyBTcGxpdCBjZWxscyBpbnRvIGdyb3VwcyBvZiBzZXhlcwpmZW1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gImZlbWFsZSIpLCBdCm1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gIm1hbGUiKSwgXQpwcmVfZGV0X2NlbGxzIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJwcmUtZGV0IiksIF0KCiMjIGluc3BlY3QgcmFuZ2Ugb2YgcHQgdmFsdWVzIHRvIGRldGVybWluZSBiaW4gd2lkdGgKaGlzdChmZW1hbGVfY2VsbHMkUFRfTGluZWFnZUZlbWFsZSkKaGlzdChtYWxlX2NlbGxzJFBUX0xpbmVhZ2VNYWxlKQpoaXN0KHByZV9kZXRfY2VsbHMkUFRfTGluZWFnZUZlbWFsZSkKaGlzdChwcmVfZGV0X2NlbGxzJFBUX0xpbmVhZ2VNYWxlKQoKYGBgCgpVc2UgYSBiaW4gd2lkdGggb2YgMgoKdGhlcmUgd2lsbCBiZSB0d28gb2JqZWN0cyBmb3IgdGhlIGNlbGxfZ3JvdXBfZGY6IG1hbGUgYnJhbmNoIGFuZCBmZW1hbGUgYnJhbmNoLiBCb3RoIHdpbGwgaW5jbHVkZSB0aGUgcHJlLWRldCBicmFuY2gKCmBgYHtyfQojIyBEZWZpbmUgbWFsZSBhbmQgZmVtYWxlIGJyYW5jaCBjZWxscwojIG1hbGUKbWFsZV9icmFuY2hfbWV0YV9kYXRhIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJwcmUtZGV0IiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gIm1hbGUiKSwgXQoKbWFsZV9icmFuY2hfbWV0YV9kYXRhIDwtIGRhdGEuZnJhbWUoY2VsbF9pZCA9IHJvd25hbWVzKG1hbGVfYnJhbmNoX21ldGFfZGF0YSksIHB0ID0gbWFsZV9icmFuY2hfbWV0YV9kYXRhJFBUX0xpbmVhZ2VNYWxlKQoKbWFsZV9jZWxsX2dyb3VwX2RmIDwtIG1hbGVfYnJhbmNoX21ldGFfZGF0YQoKI2ZlbWFsZQpmZW1hbGVfYnJhbmNoX21ldGFfZGF0YSA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAicHJlLWRldCIgfCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJmZW1hbGUiKSwgXQoKZmVtYWxlX2JyYW5jaF9tZXRhX2RhdGEgPC0gZGF0YS5mcmFtZShjZWxsX2lkID0gcm93bmFtZXMoZmVtYWxlX2JyYW5jaF9tZXRhX2RhdGEpLCBwdCA9IGZlbWFsZV9icmFuY2hfbWV0YV9kYXRhJFBUX0xpbmVhZ2VGZW1hbGUpCgpmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBmZW1hbGVfYnJhbmNoX21ldGFfZGF0YQoKIyMgd2hhdCdzIHRoZSByYW5nZSBvZiB2YWx1ZXMgZm9yIGVhY2ggcHQ/CgpyYW5nZShmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCkKcmFuZ2UobWFsZV9jZWxsX2dyb3VwX2RmJHB0KQpgYGAKCmBgYHtyfQojIyBtYWtlIGJpbiB3aWR0aHMKIyBtYWtlIGEgbmV3IGNvbCBmb3IgYW5ub3RhdGlvbgpmZW1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4gPC0gTkEKZm9yKGkgaW4gc2VxKDIsNjgsMikpewogIGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA8IGkgJiBmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA+PSAoaS0yKSldIDwtIGkKfQoKbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbiA8LSBOQQpmb3IoaSBpbiBzZXEoMiw2OCwyKSl7CiAgbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChtYWxlX2NlbGxfZ3JvdXBfZGYkcHQgPCBpICYgbWFsZV9jZWxsX2dyb3VwX2RmJHB0ID49IChpLTIpKV0gPC0gaQp9CiMgdGhlbiByZW1vdmUgb2xkIHB0IHZhbHVlcwptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmBgYAoKYGBge3J9CiMjIFRoZSBvcmlnaW5hbCBvYmplY3QgY29udGFpbnMgYWxsIGNlbGxzLCB3ZSBqdXN0IHdhbnQgd2lsZC10eXBlIHNvIGxldCdzIHN1YnNldCBvdXQgZ2VuZV9tb2R1bGVfZGYgYW5kIGNlbGxfZ3JvdXBfZGYgYWNjb3JkaW5nbHkKCiMjIG1hbGUKIyMgc3Vic2V0IG91dCBvbmx5IG1hbGUgYW5kIHByZSBkZXRlcm1pbmF0aW9uIGNlbGxzCm1hbGVfY2VsbHMgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gIm1hbGUiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAicHJlLWRldCIpLCBdCiMjIHRha2UgZm9yd2FyZCBvbmx5IHdpbGQtdHlwZQptYWxlX2NlbGxzIDwtIG1hbGVfY2VsbHNbd2hpY2gobWFsZV9jZWxscyRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1QiIHwgbWFsZV9jZWxscyRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksIF0KI21hbGVfY2VsbHMgPC0gbWFsZV9jZWxsc1t3aGljaChtYWxlX2NlbGxzJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSwgXQojIyBnZXQgY2VsbCBuYW1lcwptYWxlX2NlbGxzIDwtIHJvd25hbWVzKG1hbGVfY2VsbHMpCiMjIHN1YnNldCBvdXIgY2VsbCBncm91cCBkZiB0byBrZWVwIG9ubHkgdGhlc2UgY2VsbHMKbWFsZV9jZWxsX2dyb3VwX2RmIDwtIG1hbGVfY2VsbF9ncm91cF9kZlt3aGljaChtYWxlX2NlbGxfZ3JvdXBfZGYkY2VsbF9pZCAlaW4lIG1hbGVfY2VsbHMpLF0KIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gY29udGFpbiBjZWxscyBvZiBpbnRlcmVzdCAgCm1hbGUuc2V1cmF0Lm9iamVjdCA8LSBTdWJzZXREYXRhKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscyA9IG1hbGVfY2VsbHMpCiMjIG1ha2UgbmV3IGNvdW50cyBhbmQgcGhlbm86CmRhdGEgPC0gYXMoYXMubWF0cml4KEdldEFzc2F5RGF0YShtYWxlLnNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUobWFsZS5zZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkKIyMga2VlcCBvbmx5IHRoZSBjb2x1bW5zIHRoYXQgYXJlIHJlbGV2YW50CiNwRGF0YSA8LSBwZCAlPiUgc2VsZWN0KG9yaWcuaWRlbnQsIG5Db3VudF9STkEsIG5GZWF0dXJlX1JOQSkKZkRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3cubmFtZXMoZGF0YSksIHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhkYXRhKSkKIyMgQ29uc3RydWN0IG1vbm9jbGUgY2RzCm1hbGUubW9ub2NsZS5vYmplY3QgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCiMjIHByZXByb2Nlc3MKbWFsZS5tb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKG1hbGUubW9ub2NsZS5vYmplY3QsIG51bV9kaW0gPSA1MCwgbm9ybV9tZXRob2QgPSAibm9uZSIpICAKIyMgbWFrZSBhIG5ldyBkYXRhZnJhbWUgZm9yIGNlbGwgZ3JvdXBzIC0gaXQgaXMgY3J1Y2lhbCB0byByZWZhY3RvciBvdGhlcndpc2UgYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbiB0aGlua3MgaXQncyBvdXQgb2YgYm91bmRzICAKbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGRhdGEuZnJhbWUoY2VsbD1hcy5jaGFyYWN0ZXIoZmFjdG9yKG1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkKSksIGNlbGxfZ3JvdXA9ZmFjdG9yKG1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4pKSAgCiMjIGFnZ3JlZ2F0ZSBleHByZXNzaW9uCm1hbGVfYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1hbGUubW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgbWFsZV9jZWxsX2dyb3VwX2RmLCBleGNsdWRlLm5hID0gRkFMU0UpCgojIyBmZW1hbGUKIyMgc3Vic2V0IG91dCBvbmx5IG1hbGUgYW5kIHByZSBkZXRlcm1pbmF0aW9uIGNlbGxzCmZlbWFsZV9jZWxscyA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAiZmVtYWxlIiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gInByZS1kZXQiKSwgXQojIyB0YWtlIGZvcndhcmQgb25seSB3aWxkLXR5cGUKZmVtYWxlX2NlbGxzIDwtIGZlbWFsZV9jZWxsc1t3aGljaChmZW1hbGVfY2VsbHMkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUIiB8IGZlbWFsZV9jZWxscyRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksIF0KI2ZlbWFsZV9jZWxscyA8LSBmZW1hbGVfY2VsbHNbd2hpY2goZmVtYWxlX2NlbGxzJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSwgXQojIyBnZXQgY2VsbCBuYW1lcwpmZW1hbGVfY2VsbHMgPC0gcm93bmFtZXMoZmVtYWxlX2NlbGxzKQojIyBzdWJzZXQgb3VyIGNlbGwgZ3JvdXAgZGYgdG8ga2VlcCBvbmx5IHRoZXNlIGNlbGxzCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmW3doaWNoKGZlbWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQgJWluJSBmZW1hbGVfY2VsbHMpLF0KIyMgc3Vic2V0IFNldXJhdCBvYmplY3QgdG8gY29udGFpbiBjZWxscyBvZiBpbnRlcmVzdCAgCmZlbWFsZS5zZXVyYXQub2JqZWN0IDwtIFN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gZmVtYWxlX2NlbGxzKQojIyBtYWtlIG5ldyBjb3VudHMgYW5kIHBoZW5vOgpkYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEoZmVtYWxlLnNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUoZmVtYWxlLnNldXJhdC5vYmplY3RAbWV0YS5kYXRhKQojIyBrZWVwIG9ubHkgdGhlIGNvbHVtbnMgdGhhdCBhcmUgcmVsZXZhbnQKI3BEYXRhIDwtIHBkICU+JSBzZWxlY3Qob3JpZy5pZGVudCwgbkNvdW50X1JOQSwgbkZlYXR1cmVfUk5BKQpmRGF0YSA8LSBkYXRhLmZyYW1lKGdlbmVfc2hvcnRfbmFtZSA9IHJvdy5uYW1lcyhkYXRhKSwgcm93Lm5hbWVzID0gcm93Lm5hbWVzKGRhdGEpKQojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKZmVtYWxlLm1vbm9jbGUub2JqZWN0IDwtIG5ld19jZWxsX2RhdGFfc2V0KGV4cHJlc3Npb25fZGF0YSA9IGRhdGEsIGNlbGxfbWV0YWRhdGEgPSBwZCwgZ2VuZV9tZXRhZGF0YSA9IGZEYXRhKQojIyBwcmVwcm9jZXNzCmZlbWFsZS5tb25vY2xlLm9iamVjdCA9IHByZXByb2Nlc3NfY2RzKGZlbWFsZS5tb25vY2xlLm9iamVjdCwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikgIAojIyBtYWtlIGEgbmV3IGRhdGFmcmFtZSBmb3IgY2VsbCBncm91cHMgLSBpdCBpcyBjcnVjaWFsIHRvIHJlZmFjdG9yIG90aGVyd2lzZSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uIHRoaW5rcyBpdCdzIG91dCBvZiBib3VuZHMgIApmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGw9YXMuY2hhcmFjdGVyKGZhY3RvcihmZW1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkKSksIGNlbGxfZ3JvdXA9ZmFjdG9yKGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbikpICAKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KZmVtYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihmZW1hbGUubW9ub2NsZS5vYmplY3QsIGdlbmVfbW9kdWxlX2RmX3NleCwgZmVtYWxlX2NlbGxfZ3JvdXBfZGYsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDV9CiMjIHVzZSB0aGVzZSBjbHVzdGVycyB0byByZW9yZGVyIHRoZSBtb2R1bGVzCm1hbGVfYWdnX21hdCA8LSBtYWxlX2FnZ19tYXRbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMobWFsZV9hZ2dfbWF0KSksIF0KZmVtYWxlX2FnZ19tYXQgPC0gZmVtYWxlX2FnZ19tYXRbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMoZmVtYWxlX2FnZ19tYXQpKSwgXQoKcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKQoKcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0iY29sdW1uIiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKQoKcGhlYXRtYXA6OnBoZWF0bWFwKG1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0ibm9uZSIsCiAgICAgICAgICAgICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSkKCnBoZWF0bWFwOjpwaGVhdG1hcChmZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKQoKcGhlYXRtYXA6OnBoZWF0bWFwKGZlbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCgpwaGVhdG1hcDo6cGhlYXRtYXAoZmVtYWxlX2FnZ19tYXQsIAogICAgICAgICAgICAgICAgICAgc2NhbGU9Im5vbmUiLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCgpgYGAKCkNvbXBsZXhIZWF0bWFwIHZlcnNpb24KYGBge3IsIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9CiMjIHBoZWF0bWFwIGNhbGN1bGF0ZXMgWiBzY29yZXMgZm9yIHBsb3R0aW5nIHZhbHVlcwpzY2FsZV9tYXRyaXhfYnlfY29scyA8LSBmdW5jdGlvbiAoeCkgCnsKICAgIG0gPSBhcHBseSh4LCAxLCBtZWFuLCBuYS5ybSA9IFQpCiAgICBzID0gYXBwbHkoeCwgMSwgc2QsIG5hLnJtID0gVCkKICAgIHJldHVybigoeCAtIG0pL3MpCn0KCiMjIGNhbGN1bGF0ZSB6IHNjb3JlIGJ5IGNvbApmZW1hbGVfYWdnX21hdF9zY2FsZWQgPC0gdChhcy5tYXRyaXgoc2NhbGVfbWF0cml4X2J5X2NvbHModChmZW1hbGVfYWdnX21hdCkpKSkKbWFsZV9hZ2dfbWF0X3NjYWxlZCA8LSB0KGFzLm1hdHJpeChzY2FsZV9tYXRyaXhfYnlfY29scyh0KG1hbGVfYWdnX21hdCkpKSkKIyMgcmVvcmRlciBjb2xzCmZlbWFsZV9hZ2dfbWF0X3NjYWxlZCA8LSBmZW1hbGVfYWdnX21hdF9zY2FsZWRbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMoZmVtYWxlX2FnZ19tYXRfc2NhbGVkKSksIF0KbWFsZV9hZ2dfbWF0X3NjYWxlZCA8LSBtYWxlX2FnZ19tYXRfc2NhbGVkW21hdGNoKGxldmVscyhnZW5lX21vZHVsZV9kZl9zZXgkbW9kdWxlKSwgcm93Lm5hbWVzKG1hbGVfYWdnX21hdF9zY2FsZWQpKSwgXQoKIyMgcmVvcmRlciBiYXNlZCBvbiBjbHVzdGVycwpnZW5lc19wZXJfbW9kdWxlIDwtIGdlbmVzX3Blcl9tb2R1bGVbbWF0Y2gobGV2ZWxzKGdlbmVfbW9kdWxlX2RmX3NleCRtb2R1bGUpLCByb3cubmFtZXMoZ2VuZXNfcGVyX21vZHVsZSkpLCBdCgojIyBjaGFuZ2UgbmFtZXMgZm9yIHJvdyBuYW1lcyB0byBpbmNsdWRlICJtb2R1bGUgIiBhdCB0aGUgYmVnaW5pbmcgb2YgdGhlbQpyb3cubmFtZXMoZmVtYWxlX2FnZ19tYXRfc2NhbGVkKSA8LSBzdHJpbmdyOjpzdHJfYygiTW9kdWxlICIsIHJvdy5uYW1lcyhmZW1hbGVfYWdnX21hdF9zY2FsZWQpKQpyb3cubmFtZXMobWFsZV9hZ2dfbWF0X3NjYWxlZCkgPC0gc3RyaW5ncjo6c3RyX2MoIk1vZHVsZSAiLCByb3cubmFtZXMobWFsZV9hZ2dfbWF0X3NjYWxlZCkpCgojIyBhZGQgbnVtYmVyIG9mIGNlbGxzIHRvIHRoZSByb3duYW1lcyBmb3IgdGhlIG1vZHVsZQpmb3IoaSBpbiBzZXFfYWxvbmcoZ2VuZXNfcGVyX21vZHVsZSRGcmVxKSl7CiAgcm93Lm5hbWVzKGZlbWFsZV9hZ2dfbWF0X3NjYWxlZClbaV0gPC0gc3RyaW5ncjo6c3RyX2Mocm93Lm5hbWVzKGZlbWFsZV9hZ2dfbWF0X3NjYWxlZClbaV0sIiAobiA9ICIgLGdlbmVzX3Blcl9tb2R1bGUkRnJlcVtpXSwgIikiKQp9CmZvcihpIGluIHNlcV9hbG9uZyhnZW5lc19wZXJfbW9kdWxlJEZyZXEpKXsKICByb3cubmFtZXMobWFsZV9hZ2dfbWF0X3NjYWxlZClbaV0gPC0gc3RyaW5ncjo6c3RyX2Mocm93Lm5hbWVzKG1hbGVfYWdnX21hdF9zY2FsZWQpW2ldLCIgKG4gPSAiICxnZW5lc19wZXJfbW9kdWxlJEZyZXFbaV0sICIpIikKfQoKIyMgYWRkIGFubm90YXRpb246CiNoZWF0bWFwX2Fubm90YXRpb24gPC0gSGVhdG1hcEFubm90YXRpb24oZGYgPSBjbHVzdGVyX2Fubm8sCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGxpc3QoCiMgSWRlbnRpdHkgPSBjKE1hbGU9IiMwMTZjMDAiLCBGZW1hbGU9IiNhNTJiMWUiLCBBc2V4dWFsPSAiIzAwNTJjNSIsIENvbW1pdHRlZCA9ICIjZjJlYjIzIikpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2xlZ2VuZF9wYXJhbSA9IGxpc3QoTWVkaWFuX1BzZXVkb3RpbWVfb2ZfQ2x1c3RlciA9IGxpc3QoZGlyZWN0aW9uID0gImhvcml6b250YWwiKSwgSWRlbnRpdHkgPSBsaXN0KG5yb3cgPSAxKSkpCgpsaWJyYXJ5KENvbXBsZXhIZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbW9kdWxlc19oZWF0bWFwX2ZlbWFsZSA8LSBIZWF0bWFwKGZlbWFsZV9hZ2dfbWF0X3NjYWxlZCwKICAgICAgICBjb2x1bW5fb3JkZXIgPSBOVUxMLAogICAgICAgICNyb3dfb3JkZXIgPSByb3cubmFtZXMoZmVtYWxlX2FnZ19tYXRfc2NhbGVkKVttb2R1bGVfZGVuZHJvJG9yZGVyXSwKICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Rfcm93cyA9ICJ3YXJkLkQyIiwKICAgICAgICAjYm90dG9tX2Fubm90YXRpb24gPSBoZWF0bWFwX2Fubm90YXRpb24sCiAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9CiAgIlJkWWxCdSIpKSkoMTAwKSwgCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgptb2R1bGVzX2hlYXRtYXBfbWFsZSA8LSBIZWF0bWFwKG1hbGVfYWdnX21hdF9zY2FsZWQsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICAjcm93X29yZGVyID0gbW9kdWxlX2RlbmRybyRvcmRlciwKICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Rfcm93cyA9ICJ3YXJkLkQyIiwKICAgICAgICAjYm90dG9tX2Fubm90YXRpb24gPSBoZWF0bWFwX2Fubm90YXRpb24sCiAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9CiAgIlJkWWxCdSIpKSkoMTAwKSwgCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgpkcmF3KG1vZHVsZXNfaGVhdG1hcF9mZW1hbGUsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmRyYXcobW9kdWxlc19oZWF0bWFwX21hbGUsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCgojIyBodHRwczovL3d3dy5iaW9zdGFycy5vcmcvcC8zODA1NDQvIApgYGAKCjQgYmluIHdpZHRoIAoKYGBge3J9CiMjIERlZmluZSBtYWxlIGFuZCBmZW1hbGUgYnJhbmNoIGNlbGxzCiMgbWFsZQptYWxlX2JyYW5jaF9tZXRhX2RhdGEgPC0gdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gInByZS1kZXQiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAibWFsZSIpLCBdCgptYWxlX2JyYW5jaF9tZXRhX2RhdGEgPC0gZGF0YS5mcmFtZShjZWxsX2lkID0gcm93bmFtZXMobWFsZV9icmFuY2hfbWV0YV9kYXRhKSwgcHQgPSBtYWxlX2JyYW5jaF9tZXRhX2RhdGEkUFRfTGluZWFnZU1hbGUpCgptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9icmFuY2hfbWV0YV9kYXRhCgojZmVtYWxlCmZlbWFsZV9icmFuY2hfbWV0YV9kYXRhIDwtIHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJwcmUtZGV0IiB8IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gImZlbWFsZSIpLCBdCgpmZW1hbGVfYnJhbmNoX21ldGFfZGF0YSA8LSBkYXRhLmZyYW1lKGNlbGxfaWQgPSByb3duYW1lcyhmZW1hbGVfYnJhbmNoX21ldGFfZGF0YSksIHB0ID0gZmVtYWxlX2JyYW5jaF9tZXRhX2RhdGEkUFRfTGluZWFnZUZlbWFsZSkKCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9icmFuY2hfbWV0YV9kYXRhCgojIyB3aGF0J3MgdGhlIHJhbmdlIG9mIHZhbHVlcyBmb3IgZWFjaCBwdD8KCnJhbmdlKGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0KQpyYW5nZShtYWxlX2NlbGxfZ3JvdXBfZGYkcHQpCmBgYAoKCmBgYHtyfQojIyBtYWtlIGJpbiB3aWR0aHMKIyBtYWtlIGEgbmV3IGNvbCBmb3IgYW5ub3RhdGlvbgpmZW1hbGVfY2VsbF9ncm91cF9kZiRwdF9iaW4gPC0gTkEKZm9yKGkgaW4gc2VxKDQsNjgsNCkpewogIGZlbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA8IGkgJiBmZW1hbGVfY2VsbF9ncm91cF9kZiRwdCA+PSAoaS00KSldIDwtIGkKfQoKbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbiA8LSBOQQpmb3IoaSBpbiBzZXEoNCw2OCw0KSl7CiAgbWFsZV9jZWxsX2dyb3VwX2RmJHB0X2Jpblt3aGljaChtYWxlX2NlbGxfZ3JvdXBfZGYkcHQgPCBpICYgbWFsZV9jZWxsX2dyb3VwX2RmJHB0ID49IChpLTQpKV0gPC0gaQp9CiMgdGhlbiByZW1vdmUgb2xkIHB0IHZhbHVlcwptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGZlbWFsZV9jZWxsX2dyb3VwX2RmWyAsLTJdCmBgYAoKYGBge3J9CiMjIFRoZSBvcmlnaW5hbCBvYmplY3QgY29udGFpbnMgYWxsIGNlbGxzLCB3ZSBqdXN0IHdhbnQgd2lsZC10eXBlIHNvIGxldCdzIHN1YnNldCBvdXQgZ2VuZV9tb2R1bGVfZGYgYW5kIGNlbGxfZ3JvdXBfZGYgYWNjb3JkaW5nbHkKCiMjIG1hbGUKIyMgc3Vic2V0IG91ciBjZWxsIGdyb3VwIGRmIHRvIGtlZXAgb25seSB0aGVzZSBjZWxscwptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gbWFsZV9jZWxsX2dyb3VwX2RmW3doaWNoKG1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkICVpbiUgbWFsZV9jZWxscyksXQojIyBtYWtlIGEgbmV3IGRhdGFmcmFtZSBmb3IgY2VsbCBncm91cHMgLSBpdCBpcyBjcnVjaWFsIHRvIHJlZmFjdG9yIG90aGVyd2lzZSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uIHRoaW5rcyBpdCdzIG91dCBvZiBib3VuZHMgIAptYWxlX2NlbGxfZ3JvdXBfZGYgPC0gZGF0YS5mcmFtZShjZWxsPWFzLmNoYXJhY3RlcihmYWN0b3IobWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQpKSwgY2VsbF9ncm91cD1mYWN0b3IobWFsZV9jZWxsX2dyb3VwX2RmJHB0X2JpbikpICAKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KbWFsZV9hZ2dfbWF0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obWFsZS5tb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBtYWxlX2NlbGxfZ3JvdXBfZGYsIGV4Y2x1ZGUubmEgPSBGQUxTRSkKCiMjIGZlbWFsZQojIyBzdWJzZXQgb3V0IG9ubHkgbWFsZSBhbmQgcHJlIGRldGVybWluYXRpb24gY2VsbHMKIyMgc3Vic2V0IG91ciBjZWxsIGdyb3VwIGRmIHRvIGtlZXAgb25seSB0aGVzZSBjZWxscwpmZW1hbGVfY2VsbF9ncm91cF9kZiA8LSBmZW1hbGVfY2VsbF9ncm91cF9kZlt3aGljaChmZW1hbGVfY2VsbF9ncm91cF9kZiRjZWxsX2lkICVpbiUgZmVtYWxlX2NlbGxzKSxdCiMjIG1ha2UgYSBuZXcgZGF0YWZyYW1lIGZvciBjZWxsIGdyb3VwcyAtIGl0IGlzIGNydWNpYWwgdG8gcmVmYWN0b3Igb3RoZXJ3aXNlIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24gdGhpbmtzIGl0J3Mgb3V0IG9mIGJvdW5kcyAgCmZlbWFsZV9jZWxsX2dyb3VwX2RmIDwtIGRhdGEuZnJhbWUoY2VsbD1hcy5jaGFyYWN0ZXIoZmFjdG9yKGZlbWFsZV9jZWxsX2dyb3VwX2RmJGNlbGxfaWQpKSwgY2VsbF9ncm91cD1mYWN0b3IoZmVtYWxlX2NlbGxfZ3JvdXBfZGYkcHRfYmluKSkgIAojIyBhZ2dyZWdhdGUgZXhwcmVzc2lvbgpmZW1hbGVfYWdnX21hdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKGZlbWFsZS5tb25vY2xlLm9iamVjdCwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBmZW1hbGVfY2VsbF9ncm91cF9kZiwgZXhjbHVkZS5uYSA9IEZBTFNFKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KIyMgdXNlIHRoZXNlIGNsdXN0ZXJzIHRvIHJlb3JkZXIgdGhlIG1vZHVsZXMKbWFsZV9hZ2dfbWF0IDwtIG1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtYWxlX2FnZ19tYXQpKSwgXQpmZW1hbGVfYWdnX21hdCA8LSBmZW1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhmZW1hbGVfYWdnX21hdCkpLCBdCgpwaGVhdG1hcDo6cGhlYXRtYXAobWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UpCgpwaGVhdG1hcDo6cGhlYXRtYXAoZmVtYWxlX2FnZ19tYXQsIAogICAgICAgICAgICAgICAgICAgc2NhbGU9InJvdyIsCiAgICAgICAgICAgICAgICAgICAjY2x1c3RlcmluZ19tZXRob2Q9IndhcmQuRDIiLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHMgPSBGQUxTRSkKCmBgYAoKCgojIyMjIGV4cHJlc3Npb24gb2YgbW9kdWxlcyBpbiBtdXRhbnQgY2VsbHMgKHNpZGUgcGFuZWxzKQoKbWFsZQpgYGB7cn0KIyMgbWFrZSBtb25vY2xlIG9iamVjdCB3aXRoIG11dGFudHMKIyMgZXh0cmFjdCBkYXRhCm11dGFudF9jZWxsc19tYWxlIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWQgPT0gIk11dGFudCIgJiB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJtYWxlIiksXSkKCiMjIG1ha2UgYSBuZXcgU2V1cmF0IG9mIHRoaXMKc2V1cmF0Lm9iamVjdCA8LVN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gbXV0YW50X2NlbGxzX21hbGUpCgojIyBtYWtlIG5ldyBjb3VudHMgYW5kIHBoZW5vOgojIyB0aGUgcmVhc29uIHdlIHVzZSB0aGUgaW50ZWdyYXRlZCBhbmQgdGhlbiBzdWJzZXR0ZWQgaXMgYmVjYXVzZSB0aGVzZSBjZWxscyBoYXZlIGJlZW4gbm9ybWFsaXNlZCB3aGVyZWFzIHRoZSBjZWxscyBpbiBwYl9zZXhfZmlsdGVyZWQgaGF2ZSBub3QgYmVlbiBub3JtYWxpc2VkICh3ZWxsIHRoZXkgaGF2ZSBidXQgd2l0aCBkb3VibGV0cyBpbiB0aGVtKQpkYXRhIDwtIGFzKGFzLm1hdHJpeChHZXRBc3NheURhdGEoc2V1cmF0Lm9iamVjdCwgYXNzYXkgPSAiUk5BIiwgc2xvdCA9ICJkYXRhIikpLCAnc3BhcnNlTWF0cml4JykKcGQgPC0gZGF0YS5mcmFtZShzZXVyYXQub2JqZWN0QG1ldGEuZGF0YSkKZkRhdGEgPC0gZGF0YS5mcmFtZShnZW5lX3Nob3J0X25hbWUgPSByb3cubmFtZXMoZGF0YSksIHJvdy5uYW1lcyA9IHJvdy5uYW1lcyhkYXRhKSkKCiMjIENvbnN0cnVjdCBtb25vY2xlIGNkcwptb25vY2xlLm9iamVjdC5tdXRhbnRzLm1hbGUgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCgojIyBwcmVwcm9jZXNzCm1vbm9jbGUub2JqZWN0Lm11dGFudHMubWFsZSA9IHByZXByb2Nlc3NfY2RzKG1vbm9jbGUub2JqZWN0Lm11dGFudHMubWFsZSwgbnVtX2RpbSA9IDUwLCBub3JtX21ldGhvZCA9ICJub25lIikKIyMjIGlmIHVzaW5nIGludGVncmF0ZWQgZGF0YToKIyBub3JtX21ldGhvZCA9ICJub25lIiwgYWxpZ25tZW50X2dyb3VwID0gIn4gZXhwZXJpbWVudCIKCiMjIG1ha2UgYSBjZWxsIGdyb3VwIGRhdGFmcmFtZSBmb3IgYWdncmVnYXRpbmcgZXhwcmVzc2lvbiB2YWx1ZXM6CgptdXRhbnRfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGwgPSByb3cubmFtZXMobW9ub2NsZS5vYmplY3QubXV0YW50cy5tYWxlQGNvbERhdGEpLCBjZWxsX2dyb3VwID0gbW9ub2NsZS5vYmplY3QubXV0YW50cy5tYWxlQGNvbERhdGEkaWRlbnRpdHlfdXBkYXRlZCkKCiMjIGFnZ3JlZ2F0ZSBleHByZXNzaW9uCm11dGFudF9tYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdC5tdXRhbnRzLm1hbGUsIGdlbmVfbW9kdWxlX2RmX3NleCwgbXV0YW50X2NlbGxfZ3JvdXBfZGYpCmBgYAoKcGxvdApgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDV9Cm11dGFudF9tYWxlX2FnZ19tYXQgPC0gbXV0YW50X21hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfbWFsZV9hZ2dfbWF0KSksIF0KCnBoZWF0bWFwOjpwaGVhdG1hcChtdXRhbnRfbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDcsIGZpZy53aWR0aCA9IDV9Cm11dGFudF9tYWxlX2FnZ19tYXQgPC0gbXV0YW50X21hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfbWFsZV9hZ2dfbWF0KSksIF0KCnBoZWF0bWFwOjpwaGVhdG1hcChtdXRhbnRfbWFsZV9hZ2dfbWF0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJjb2x1bW4iLAogICAgICAgICAgICAgICAgICAgI2NsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gVFJVRSkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKYGBgCgpmZW1hbGUKYGBge3J9CiMjIG1ha2UgbW9ub2NsZSBvYmplY3Qgd2l0aCBtdXRhbnRzCiMjIGV4dHJhY3QgZGF0YQptdXRhbnRfY2VsbHNfZmVtYWxlIDwtIHJvd25hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkZ2Vub3R5cGVfY29tYmluZWQgPT0gIk11dGFudCIgJiB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkc2V4ID09ICJmZW1hbGUiKSxdKQoKIyMgbWFrZSBhIG5ldyBTZXVyYXQgb2YgdGhpcwpzZXVyYXQub2JqZWN0IDwtU3Vic2V0RGF0YSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgY2VsbHMgPSBtdXRhbnRfY2VsbHNfZmVtYWxlKQoKIyMgbWFrZSBuZXcgY291bnRzIGFuZCBwaGVubzoKIyMgdGhlIHJlYXNvbiB3ZSB1c2UgdGhlIGludGVncmF0ZWQgYW5kIHRoZW4gc3Vic2V0dGVkIGlzIGJlY2F1c2UgdGhlc2UgY2VsbHMgaGF2ZSBiZWVuIG5vcm1hbGlzZWQgd2hlcmVhcyB0aGUgY2VsbHMgaW4gcGJfc2V4X2ZpbHRlcmVkIGhhdmUgbm90IGJlZW4gbm9ybWFsaXNlZCAod2VsbCB0aGV5IGhhdmUgYnV0IHdpdGggZG91YmxldHMgaW4gdGhlbSkKZGF0YSA8LSBhcyhhcy5tYXRyaXgoR2V0QXNzYXlEYXRhKHNldXJhdC5vYmplY3QsIGFzc2F5ID0gIlJOQSIsIHNsb3QgPSAiZGF0YSIpKSwgJ3NwYXJzZU1hdHJpeCcpCnBkIDwtIGRhdGEuZnJhbWUoc2V1cmF0Lm9iamVjdEBtZXRhLmRhdGEpCmZEYXRhIDwtIGRhdGEuZnJhbWUoZ2VuZV9zaG9ydF9uYW1lID0gcm93Lm5hbWVzKGRhdGEpLCByb3cubmFtZXMgPSByb3cubmFtZXMoZGF0YSkpCgojIyBDb25zdHJ1Y3QgbW9ub2NsZSBjZHMKbW9ub2NsZS5vYmplY3QubXV0YW50cy5mZW1hbGUgPC0gbmV3X2NlbGxfZGF0YV9zZXQoZXhwcmVzc2lvbl9kYXRhID0gZGF0YSwgY2VsbF9tZXRhZGF0YSA9IHBkLCBnZW5lX21ldGFkYXRhID0gZkRhdGEpCgojIyBwcmVwcm9jZXNzCm1vbm9jbGUub2JqZWN0Lm11dGFudHMuZmVtYWxlID0gcHJlcHJvY2Vzc19jZHMobW9ub2NsZS5vYmplY3QubXV0YW50cy5mZW1hbGUsIG51bV9kaW0gPSA1MCwgbm9ybV9tZXRob2QgPSAibm9uZSIpCiMjIyBpZiB1c2luZyBpbnRlZ3JhdGVkIGRhdGE6CiMgbm9ybV9tZXRob2QgPSAibm9uZSIsIGFsaWdubWVudF9ncm91cCA9ICJ+IGV4cGVyaW1lbnQiCgojIyBtYWtlIGEgY2VsbCBncm91cCBkYXRhZnJhbWUgZm9yIGFnZ3JlZ2F0aW5nIGV4cHJlc3Npb24gdmFsdWVzOgptdXRhbnRfY2VsbF9ncm91cF9kZiA8LSBkYXRhLmZyYW1lKGNlbGwgPSByb3cubmFtZXMobW9ub2NsZS5vYmplY3QubXV0YW50cy5mZW1hbGVAY29sRGF0YSksIGNlbGxfZ3JvdXAgPSBtb25vY2xlLm9iamVjdC5tdXRhbnRzLmZlbWFsZUBjb2xEYXRhJGlkZW50aXR5X3VwZGF0ZWQpCgojIyBhZ2dyZWdhdGUgZXhwcmVzc2lvbgptdXRhbnRfZmVtYWxlX2FnZ19tYXQgPC0gYWdncmVnYXRlX2dlbmVfZXhwcmVzc2lvbihtb25vY2xlLm9iamVjdC5tdXRhbnRzLmZlbWFsZSwgZ2VuZV9tb2R1bGVfZGZfc2V4LCBtdXRhbnRfY2VsbF9ncm91cF9kZikKYGBgCgpwbG90CmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KbXV0YW50X2ZlbWFsZV9hZ2dfbWF0IDwtIG11dGFudF9mZW1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfZmVtYWxlX2FnZ19tYXQpKSwgXQoKcGhlYXRtYXA6OnBoZWF0bWFwKG11dGFudF9mZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0iY29sdW1uIiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IEZBTFNFKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gNX0KbXV0YW50X2ZlbWFsZV9hZ2dfbWF0IDwtIG11dGFudF9mZW1hbGVfYWdnX21hdFttYXRjaChsZXZlbHMoZ2VuZV9tb2R1bGVfZGZfc2V4JG1vZHVsZSksIHJvdy5uYW1lcyhtdXRhbnRfZmVtYWxlX2FnZ19tYXQpKSwgXQoKcGhlYXRtYXA6OnBoZWF0bWFwKG11dGFudF9mZW1hbGVfYWdnX21hdCwgCiAgICAgICAgICAgICAgICAgICBzY2FsZT0icm93IiwKICAgICAgICAgICAgICAgICAgICNjbHVzdGVyaW5nX21ldGhvZD0id2FyZC5EMiIsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29scyA9IFRSVUUpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCmBgYAoKIyMjIyBmb3IgcGFydGljdWxhciBnZW5lcyAobG93ZXIgcGFuZWwpCgpgYGB7ciwgZmlnLmhlaWdodCA9IDIsIGZpZy53aWR0aCA9IDl9CiMjIGxhbmRtYXJrIGdlbmVzIChnZW5lcyBvZiBpbnRlcmVzdCkKIyBBUDJHIC0gUEJBTktBLTE0Mzc1MDAKIyBBUDIgLSBQQkFOS0EtMDkwOTYwMCAtIGZyb20gcG9yYW4gcGFwZXIKIyBBUDJHLTIgLSBQQkFOS0EtMTAzNDMwMCAKbGlzdF9vZl9tdXRhbnRfZ2VuZXMgPC0gYygiUEJBTktBLTA4MjgwMDAiLCAiUEJBTktBLTEzMDI3MDAiLCAiUEJBTktBLTE0NDc5MDAiLCAiUEJBTktBLTAxMDI0MDAiLCAiUEJBTktBLTA3MTY1MDAiLCAiUEJBTktBLTE0MzUyMDAiLCAiUEJBTktBLTE0MTgxMDAiLCAiUEJBTktBLTExNDQ4MDAiLCAiUEJBTktBLTA5MDIzMDAiLCAiUEJBTktBLTA0MTM0MDAiLCAiUEJBTktBLTE0NTQ4MDAiKQoKbGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCA8LSBjKCJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDkwOTYwMCIsIlBCQU5LQS0xMDM0MzAwIiwgIlBCQU5LQS0wODI4MDAwIiwgIlBCQU5LQS0xMzAyNzAwIiwgIlBCQU5LQS0xNDQ3OTAwIiwgIlBCQU5LQS0wMTAyNDAwIiwgIlBCQU5LQS0wNzE2NTAwIiwgIlBCQU5LQS0xNDM1MjAwIiwgIlBCQU5LQS0xNDE4MTAwIiwgIlBCQU5LQS0xMTQ0ODAwIiwgIlBCQU5LQS0wOTAyMzAwIiwgIlBCQU5LQS0wNDEzNDAwIiwgIlBCQU5LQS0xNDU0ODAwIikKIyNtYWtlIGRmIGZvciBnZW5lcyBvZiBpbnRlcmVzdApnZW5lc19vZl9pbnRlcmVzdCA8LSBkYXRhLmZyYW1lKGdlbmUgPSBsaXN0X29mX2dlbmVzX29mX2ludGVyZXN0LCBncm91cCA9IGMoMTpsZW5ndGgobGlzdF9vZl9nZW5lc19vZl9pbnRlcmVzdCkpKQoKIyMgYWdncmVnYXRlIGV4cHJlc3Npb24KIyMgbWFrZSBwbG90dGluZyBkZgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obW9ub2NsZS5vYmplY3QsIGdlbmVzX29mX2ludGVyZXN0LCBjZWxsX2dyb3VwX2RmKQoKcm93Lm5hbWVzKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QpIDwtIGdlbmVzX29mX2ludGVyZXN0JGdlbmUKCiNyb3cubmFtZXMoYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCkgPC0gZmFjdG9yKHJvdy5uYW1lcyhhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0KSwgbGV2ZWxzID0gcm93Lm5hbWVzKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QpW21vZHVsZV9kZW5kcm8kb3JkZXJdKQphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbLG1hdGNoKHJvd25hbWVzKGNsdXN0ZXJfYW5ubyksIGNvbG5hbWVzKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QpKV0KCnBoZWF0bWFwOjpwaGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LCAKICAgICAgICAgICAgICAgICAgIHNjYWxlPSJyb3ciLAogICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2xzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kPSJ3YXJkLkQyIiwgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbCA9IGNsdXN0ZXJfYW5ubywgCiAgICAgICAgICAgICAgICAgICBhbm5vdGF0aW9uX2NvbG9ycyA9IGFubm90YXRpb25fY29sb3VycykKYGBgCgpjb21wbGV4IGhlYXQgbWFwCgpgYGB7cn0KIyMgYWdncmVnYXRlIGdlbmUgZXhwcmVzc2lvbgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ3JlZ2F0ZV9nZW5lX2V4cHJlc3Npb24obW9ub2NsZS5vYmplY3QsIGdlbmVzX29mX2ludGVyZXN0LCBkZl9hbGxfY2VsbHMpCgphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFzLm1hdHJpeChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0KQoKIyMgbWFrZSBoZWF0bWFwCm1vZHVsZXNfaGVhdG1hcCA8LSBIZWF0bWFwKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICBzaG93X2NvbHVtbl9kZW5kID0gRkFMU0UsCiAgICAgICAgY29sdW1uX2xhYmVscyA9IHJlcCgiIiwgbmNvbChhZ2dfbWF0X2FsbF9jZWxsc19tYXRyaXgpKSwKICAgICAgICAjcm93X29yZGVyID0gbW9kdWxlX2RlbmRybyRvcmRlciwKICAgICAgICBjbHVzdGVyaW5nX21ldGhvZF9jb2x1bW5zID0gIndhcmQuRDIiLAogICAgICAgIGJvdHRvbV9hbm5vdGF0aW9uID0gaGVhdG1hcF9hbm5vdGF0aW9uLAogICAgICAgIGNvbCA9IGNvbG9yUmFtcFBhbGV0dGUocmV2KGJyZXdlci5wYWwobiA9IDcsIG5hbWUgPQogICJSZFlsQnUiKSkpKDEwMCksIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdChkaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpKQoKIyMgcHJpbnQKZHJhdyhtb2R1bGVzX2hlYXRtYXAsIG1lcmdlX2xlZ2VuZCA9IFRSVUUsIGhlYXRtYXBfbGVnZW5kX3NpZGUgPSAiYm90dG9tIiwgCiAgICBhbm5vdGF0aW9uX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIpCmBgYAoKYGBge3J9CiMjIG9yZGVyIGNvbHMgaW4gdGhlIG1hdHJpeAphZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0IDwtIGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3RbICxtYXRjaChyb3duYW1lcyhkZl9hbm5vKSwgY29sbmFtZXMoYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCkpXQoKIyMgbWFrZSBoZWF0bWFwCm1vZHVsZXNfaGVhdG1hcCA8LSBIZWF0bWFwKGFnZ19tYXRfZ2VuZXNfb2ZfaW50ZXJlc3QsCiAgICAgICAgY29sdW1uX29yZGVyID0gTlVMTCwKICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBUUlVFLAogICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLAogICAgICAgIHNob3dfY29sdW1uX2RlbmQgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fbGFiZWxzID0gcmVwKCIiLCBuY29sKGFnZ19tYXRfYWxsX2NlbGxzX21hdHJpeCkpLAogICAgICAgICNyb3dfb3JkZXIgPSBtb2R1bGVfZGVuZHJvJG9yZGVyLAogICAgICAgIGNsdXN0ZXJpbmdfbWV0aG9kX2NvbHVtbnMgPSAid2FyZC5EMiIsCiAgICAgICAgYm90dG9tX2Fubm90YXRpb24gPSBoZWF0bWFwX2Fubm90YXRpb24sCiAgICAgICAgY29sID0gY29sb3JSYW1wUGFsZXR0ZShyZXYoYnJld2VyLnBhbChuID0gNywgbmFtZSA9CiAgIlJkWWxCdSIpKSkoMTAwKSwgCiAgICAgICAgaGVhdG1hcF9sZWdlbmRfcGFyYW0gPSBsaXN0KGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikpCgojIyBwcmludApkcmF3KG1vZHVsZXNfaGVhdG1hcCwgbWVyZ2VfbGVnZW5kID0gVFJVRSwgaGVhdG1hcF9sZWdlbmRfc2lkZSA9ICJib3R0b20iLCAKICAgIGFubm90YXRpb25fbGVnZW5kX3NpZGUgPSAiYm90dG9tIikKYGBgCgpVc2luZyBTZXVyYXQgdG8gdmlzdWFsaXNlIGNlbGxzCmBgYHtyfQojIGZpbmQgbWFya2VycyBmb3IgZXZlcnkgY2x1c3RlciBjb21wYXJlZCB0byBhbGwgcmVtYWluaW5nIGNlbGxzLCByZXBvcnQgb25seSB0aGUgcG9zaXRpdmUgb25lcwp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5tYXJrZXJzIDwtIEZpbmRBbGxNYXJrZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBvbmx5LnBvcyA9IFRSVUUsIG1pbi5wY3QgPSAwLjI1LCBsb2dmYy50aHJlc2hvbGQgPSAwLjI1KQp0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDIsIHd0ID0gYXZnX2xvZ0ZDKQpgYGAKCmBgYHtyfQp0b3AxMCA8LSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleC5tYXJrZXJzICU+JSBncm91cF9ieShjbHVzdGVyKSAlPiUgdG9wX24obiA9IDEwLCB3dCA9IGF2Z19sb2dGQykKRG9IZWF0bWFwKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBmZWF0dXJlcyA9IHRvcDEwJGdlbmUpICsgTm9MZWdlbmQoKQpgYGAKCkJ1dCB3ZSBhbHNvIGhhdmUgdGhlIG9sZCBwdCB2YWx1ZXMgdGhhdCB3ZSBjYW4gdXNlIGluIHRoZSBzZXVyYXQgb2JqZWN0IGllIEZlYXR1cmVQbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAicGNhIiwgcHQuc2l6ZSA9IDAuMDEsIGZlYXR1cmVzID0gIm9sZF9wdF92YWx1ZXMiKQoKU28gbGV0J3MgcGxvdCBhIGhlYXRtYXAgd2hlcmUgd2UgcGxvdDogKHgpIGFsbCBjZWxscyB2cy4gKHkpIGdlbmVzIGFycmFuZ2VkIGJ5IG1vZHVsZSB0aGF0IHRoZXkgYmVsb25nIHRvLiAKCmFkZCBhbiBvbGQgcHQgYW5ub3RhdGlvbiB0byB0aGUgdG9wCgpwcmVwYXJlIGRhdGE6CmBgYHtyfQojIyBleHRyYWN0cyBvbmx5IDEweCBjZWxscyAKd3RfY2VsbHMgPC0gcm93bmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1RfMTBYIiksXSkKCiMjIG1ha2UgYSBuZXcgU2V1cmF0IG9mIHRoaXMKc2V1cmF0Lm9iamVjdCA8LVN1YnNldERhdGEodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGNlbGxzID0gd3RfY2VsbHMpCmBgYAoKYGBge3J9CkRvSGVhdG1hcChzZXVyYXQub2JqZWN0LCBmZWF0dXJlcyA9IHRvcDEwJGdlbmUpICsgTm9MZWdlbmQoKQpgYGAKCmBgYHtyfQoKYGBgCgoKYGBge3J9CiMjIGFnZ3JlZ2F0ZSBnZW5lIGV4cHJlc3Npb24KYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCA8LSBhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKG1vbm9jbGUub2JqZWN0LCBnZW5lc19vZl9pbnRlcmVzdCwgZGZfYWxsX2NlbGxzKQoKYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCA8LSBhcy5tYXRyaXgoYWdnX21hdF9nZW5lc19vZl9pbnRlcmVzdCkKCiMjIG1ha2UgaGVhdG1hcAptb2R1bGVzX2hlYXRtYXAgPC0gSGVhdG1hcChhZ2dfbWF0X2dlbmVzX29mX2ludGVyZXN0LAogICAgICAgIGNvbHVtbl9vcmRlciA9IE5VTEwsCiAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgc2hvd19jb2x1bW5fZGVuZCA9IEZBTFNFLAogICAgICAgIGNvbHVtbl9sYWJlbHMgPSByZXAoIiIsIG5jb2woYWdnX21hdF9hbGxfY2VsbHNfbWF0cml4KSksCiAgICAgICAgI3Jvd19vcmRlciA9IG1vZHVsZV9kZW5kcm8kb3JkZXIsCiAgICAgICAgY2x1c3RlcmluZ19tZXRob2RfY29sdW1ucyA9ICJ3YXJkLkQyIiwKICAgICAgICBib3R0b21fYW5ub3RhdGlvbiA9IGhlYXRtYXBfYW5ub3RhdGlvbiwKICAgICAgICBjb2wgPSBjb2xvclJhbXBQYWxldHRlKHJldihicmV3ZXIucGFsKG4gPSA3LCBuYW1lID0KICAiUmRZbEJ1IikpKSgxMDApLCAKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoZGlyZWN0aW9uID0gImhvcml6b250YWwiKSkKCiMjIHByaW50CmRyYXcobW9kdWxlc19oZWF0bWFwLCBtZXJnZV9sZWdlbmQgPSBUUlVFLCBoZWF0bWFwX2xlZ2VuZF9zaWRlID0gImJvdHRvbSIsIAogICAgYW5ub3RhdGlvbl9sZWdlbmRfc2lkZSA9ICJib3R0b20iKQpgYGAKCkV4cHJlc3Npb24gb2YgQ0NQMiBhbmQgTUcxIGJ5IGVhY2ggZ2Vub3R5cGUgYW5kIGVhY2ggc2V4CgpgYGB7cn0KIyBjY3AyIC0gIlBCQU5LQS0xMzE5NTAwIiAtIGZlbWFsZSA4MjAKIyBNRzEgLSAiUEJBTktBLTA0MTYxMDAiIC0gbWFsZSA4MjAKCiMjIG1ha2UgYSBjdXN0b20gZGF0YWZyYW1lOgptYXJrZXJfODIwX2RmIDwtIGFzLmRhdGEuZnJhbWUodChhcy5kYXRhLmZyYW1lKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QGFzc2F5cyRSTkFAZGF0YVtjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIpLCBdLCBzdHJpbmdzQXNGYWN0b3JzPUYpKSkKbWFya2VyXzgyMF9kZiRjZWxsX2lkIDwtIHJvdy5uYW1lcyhtYXJrZXJfODIwX2RmKQpzZXhfaWQgPC0gZGF0YS5mcmFtZShzZXhfYXQgPSB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkYXRfc2V4LCBnZW5vdHlwZSA9IHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkICxjZWxsX2lkID0gcm93Lm5hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSkpCm1hcmtlcl84MjBfZGYgPC0gbWVyZ2UobWFya2VyXzgyMF9kZiwgc2V4X2lkLCBieSA9ICJjZWxsX2lkIikKCmdncGxvdChtYXJrZXJfODIwX2RmLCBhZXMoZmlsbD1zZXhfYXQsIHk9YFBCQU5LQS0xMzE5NTAwYCwgeD1nZW5vdHlwZSkpICsgCiAgICBnZW9tX3Zpb2xpbigpICsKICBnZW9tX2ppdHRlcihzaGFwZT0xNiwgcG9zaXRpb249cG9zaXRpb25faml0dGVyKDAuMikpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKQpgYGAKCmBgYHtyfQojdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRzZXggPT0gInByZS1kZXQiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJHNleCA9PSAiZmVtYWxlIiksIF0KCgpWbG5QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIiwgc3BsaXQuYnkgPSAiYXRfc2V4IiwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIpLCBzcGxpdC5wbG90ID0gVFJVRSkKClZsblBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGdyb3VwLmJ5ID0gImlkZW50aXR5X3VwZGF0ZWQiLCBzcGxpdC5ieSA9ICJhdF9zZXgiLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wNDE2MTAwIiksIHNwbGl0LnBsb3QgPSBUUlVFKQpgYGAKCkRpZmZlcmVudGlhbCBleHByZXNzaW9uCgpSZS1jbHVzdGVyIHRoZSBkYXRhIHNvIHdlIGhhdmUgdmVyeSBjb3Vyc2UgZ3JhaW4gY2x1c3RlcnMKYGBge3J9CiMjIGZpbmQgbmV3IGNsdXN0ZXJzCnRlbngubXV0YW50LmludGVncmF0ZWQuc2V4IDwtIEZpbmRDbHVzdGVycyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleCwgcmVzb2x1dGlvbiA9IDEsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCgojIyBwbG90IHRoZSBncmFwaApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMSIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ3VpZGVzKGNvbG91cj1ndWlkZV9sZWdlbmQobnJvdz0zLGJ5cm93PVRSVUUsIG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZT00KSkpCmBgYAoKYGBge3J9ClZsblBsb3QodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXgsIGZlYXR1cmVzID0gYygiUFRfRmVtYWxlX1VNQVAiLCAiUFRfTWFsZV9VTUFQIikpCmBgYAoKIyMjIyBTaG93IHJlcHJlc2VudGF0aW9uIG9mIGdlbm90eXBlcyBwZXIgY2x1c3RlcgoKcHJlcCBmb3IgZG90cGxvdApgYGB7cn0KIyMgbWFrZSBhIGRhdGFmcmFtZSB0aGF0IGlzIHRoZSBtZXRhIGRhdGEKZGZfbWV0YV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhKQoKIyMgZGVmaW5lIG9yZGVyIGZvciBwbG90dGluZyAKbXlfbGV2ZWxzX3NleCA8LSBjKCIyIiwgIjMiLCAiOSIsICI2IiwgIjExIiwgIjUiLCAiMCIsICIxMCIsICIxMyIsICIxNCIsICIxMiIsICI4IiwgIjE1IiwgIjEiLCAiNCIsICI3IikKCiMjIHJlZGVmaW5lIG9yZGVyIG9mIGNsdXN0ZXJzOgpkZl9tZXRhX2RhdGEkc2V1cmF0X2NsdXN0ZXJzIDwtIGZhY3Rvcih4ID0gZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgbGV2ZWxzID0gbXlfbGV2ZWxzX3NleCkKCiMjIG1ha2UgYSBuZXcgZGYgb2YgQ0xVU1RFUiBhbmQgSURFTlRJVFkKZG90X3Bsb3RfZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGFibGUoZGZfbWV0YV9kYXRhJHNldXJhdF9jbHVzdGVycywgZGZfbWV0YV9kYXRhJGlkZW50aXR5X2NvbWJpbmVkKSkKZG90X3Bsb3RfZGYkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZikKCiMjIGNhbGN1bGF0ZSBwZXJjZW50YWdlIG9mIGNlbGxzIGZvciBlYWNoIGdlbm90eXBlCmRvdF9wbG90X2RmX3BjIDwtIChhcy5kYXRhLmZyYW1lLm1hdHJpeChwcm9wLnRhYmxlKHRhYmxlKGRmX21ldGFfZGF0YSRzZXVyYXRfY2x1c3RlcnMsIGRmX21ldGFfZGF0YSRpZGVudGl0eV9jb21iaW5lZCksIG1hcmdpbiA9IDIpKSAqIDEwMCkKCiMjIG1ha2UgYSBjb2x1bW4gZm9yIGNsdXN0ZXIgbmFtZXMKZG90X3Bsb3RfZGZfcGMkY2x1c3RlciA8LSByb3duYW1lcyhkb3RfcGxvdF9kZl9wYykKCiMjIG1lbHQgZGF0YWZyYW1lIGZvciBwbG90dGluZwpsaWJyYXJ5KHJlc2hhcGUyKQpkb3RfcGxvdF9kZl9wY19tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZl9wYywgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfcGNfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCgojIyBtZWx0IHRoZSByYXcgbnVtYmVyIHRvbwpkb3RfcGxvdF9kZl9tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZiwgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCmNvbG5hbWVzKGRvdF9wbG90X2RmX21lbHRlZClbM10gPC0gInJhd19udW1iZXIiCgojIyBtZXJnZSB0b2dldGhlcgppZGVudGljYWwoZG90X3Bsb3RfZGZfbWVsdGVkJGNsdXN0ZXIsIGRvdF9wbG90X2RmX3BjX21lbHRlZCRjbHVzdGVyKQpkb3RfcGxvdF9tZXJnZWQgPC0gY2JpbmQoZG90X3Bsb3RfZGZfbWVsdGVkLCBkb3RfcGxvdF9kZl9wY19tZWx0ZWQpCmRvdF9wbG90X21lcmdlZCA8LSBkb3RfcGxvdF9tZXJnZWRbLGMoMSwyLDMsNildCgojIyByZWRlZmluZSBvcmRlciBvZiBjbHVzdGVycwpkb3RfcGxvdF9tZXJnZWQkY2x1c3RlciA8LSBmYWN0b3IoeCA9IGRvdF9wbG90X21lcmdlZCRjbHVzdGVyLCBsZXZlbHMgPSBteV9sZXZlbHNfc2V4KQoKIyMgd2hlcmUgdmFsdWVzIGFyZSB6ZXJvLCBhZGQgTkEKIyMgZmluZCB3ZWxscyB3aGVyZSBpdCdzIHplcm8KemVyb192YWx1ZXMgPC0gZG90X3Bsb3RfbWVyZ2VkJHZhbHVlID09IDAKZG90X3Bsb3RfbWVyZ2VkJHZhbHVlW3plcm9fdmFsdWVzXSA8LSBOQQoKIyMgYWxzbyBkbyBmb3IgcmF3IG51bWJlcgp6ZXJvX3ZhbHVlcyA8LSBkb3RfcGxvdF9tZXJnZWQkcmF3X251bWJlciA9PSAwCmRvdF9wbG90X21lcmdlZCRyYXdfbnVtYmVyW3plcm9fdmFsdWVzXSA8LSBOQQoKIyMgcmVvcmRlciB4IGF4aXM6Cm15X2xldmVsc19nZW5vdHlwZSA8LSBjKCJHQ1NLTy1vb20iLCAiR0NTS08tMjkiLCAiR0NTS08tMiIsICJHQ1NLTy0xOSIsICJHQ1NLTy0zIiwgIkdDU0tPLTIxIiwgIkdDU0tPLTEzIiwgIkdDU0tPLTI4IiwgIkdDU0tPLTEwXzgyMCIsICJHQ1NLTy0xNyIsICJHQ1NLTy0yMCIsICJXVCIsICJXVF8xMFgiKQoKZG90X3Bsb3RfbWVyZ2VkJGlkZW50aXR5IDwtIGZhY3Rvcih4ID0gZG90X3Bsb3RfbWVyZ2VkJGlkZW50aXR5LCBsZXZlbHMgPSBteV9sZXZlbHNfZ2Vub3R5cGUpCmBgYAoKcGxvdApgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodD0gN30KIyMgcGxvdApkb3RfcGxvdF9pZGVudGl0eSA8LSBnZ3Bsb3QoZG90X3Bsb3RfbWVyZ2VkLCBhZXMoeSA9IGZhY3RvcihjbHVzdGVyKSwgeCA9IGZhY3RvcihpZGVudGl0eSkpKSArCiAgICAgICMjIG1ha2UgaW50byBhIGRvdCBwbG90CiAgICAgIGdlb21fcG9pbnQoYWVzKGNvbG91cj12YWx1ZSwgc2l6ZT1yYXdfbnVtYmVyKSkgKyAKICAgICAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93PSJibHVlIiwgaGlnaD0icmVkIiwgbGltaXRzPWMoIDAsIG1heChkb3RfcGxvdF9kZl9wY19tZWx0ZWQkdmFsdWUpKSwgbmEudmFsdWU9IndoaXRlIikgKwogICAgICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgICAgIHNjYWxlX2NvbG91cl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIikgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKwogICAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksIHRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTYsICBmYW1pbHk9IkFyaWFsIikpICsKICAgICAgeWxhYigiQ2x1c3RlciIpICsKICAgICAgeGxhYigiSWRlbnRpdHkiKSArCiAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTEyLCBhbmdsZT00NSwgaGp1c3Q9MSwgdmp1c3Q9MSksIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTEyLCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwzKSwgImxpbmVzIikpICsKICAgICMjIGFubm90YXRlIG1hbGVzCiAgICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0ID0gMi41KSkgKwogICAgIyMgYW5ub3RhdGUgZmVtYWxlcwogICAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdCA9IDcuNSkpICsKICAgICMjIGFubm90YXRlIHBoZW5vIDEKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA0LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyAyCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gNS41KSkgKyAgICAKICAgICMjIGFubm90YXRlIHBoZW5vIDMKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSA3LjUpKSArCiAgICAjIyBhbm5vdGF0ZSBwaGVubyA0CiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0ID0gMTEuNSkpCgojIyBwcmludApwcmludChkb3RfcGxvdF9pZGVudGl0eSkKYGBgCgoKCgpjdXQgb2ZmIGFuZCBwbG90CmBgYHtyfQpwcmVfYnJhbmNoX2NlbGxzIDwtIGMoMiwzKQppbm1hdHVyZV9tYWxlX2NlbGxzIDwtIGMoKQppbm1hdHVyZV9mZW1hbGVfY2VsbHMgPC0KbWF0dXJlX21hbGVfY2VsbHMgPC0gCm1hdHVyZV9mZW1hbGVfY2VsbHMgPC0gCgojIyBwbG90IHRoZSBncmFwaApEaW1QbG90KHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCByZWR1Y3Rpb24gPSAidW1hcG9wdGltaXNlZF9wb3N0X3JlcGNhIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIGxhYmVsLnNpemUgPSA1LCBwdC5zaXplID0gMC41LCBncm91cC5ieSA9ICJpbnRlZ3JhdGVkX3Nubl9yZXMuMSIpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQpgYGAKCgoKYGBge3J9Cnd0X2NlbGxzIDwtIHJvdy5uYW1lcyh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGFbd2hpY2godGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVCIgfCB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUXzEwWCIpLCBdKQoKbWFsZV9pbm1hdHVyZV9jZWxscyA8LSByb3cubmFtZXModGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhW3doaWNoKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YSRpZGVudGl0eV9jb21iaW5lZCA9PSAiV1QiIHwgdGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAbWV0YS5kYXRhJGlkZW50aXR5X2NvbWJpbmVkID09ICJXVF8xMFgiKSwgXSkKCgoKZWFybHlfd3RfY2VsbHMgPC0gcm93Lm5hbWVzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4QG1ldGEuZGF0YVt3aGljaCh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkaWRlbnRpdHlfY29tYmluZWQgPT0gIldUIiAmJiB0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkUFRfTGluZWFnZUZlbWFsZSA8IDQ2KSwgXSkKCkZpbmRNYXJrZXJzKHRlbngubXV0YW50LmludGVncmF0ZWQuc2V4LCBjZWxscy4xID0gLCBjZWxscy4yID0gKQpgYGAKCgoKIyBTYXZlIGFuZCBFeHBvcnQgey50YWJzZXR9CgpUaGlzIHNhdmVzIGV2ZXJ5dGhpbmcgaW4gdGhlIGdsb2JhbCBlbnZpcm9ubWVudCBmb3IgZWFzeSByZWNhbGwgbGF0ZXIKYGBge3J9CnNhdmUuaW1hZ2UoZmlsZSA9ICJHQ1NLT19TZXhfQnJhbmNoX0FuYWx5c2lzLlJEYXRhIikKI2xvYWQoZmlsZSA9ICJHQ1NLT19TZXhfQnJhbmNoX0FuYWx5c2lzLlJEYXRhIikKYGBgCgpgYGB7cn0KI2dlbmVfbW9kdWxlX2RmX3NleAp3cml0ZS5jc3YoZ2VuZV9tb2R1bGVfZGZfc2V4LCBmaWxlID0gImdlbmVfbW9kdWxlX2RmX3NleC5jc3YiKQojc2F2ZShwYl8zMGtfc2V4X2ZpbHRlcmVkLCBwYl9zZXhfZmlsdGVyZWQsIGZpbGUgPSAiUGFydF8yX2lucHV0LlJkYXRhIikKYGBgCgojIEFwcGVuZGl4IHsudGFic2V0fQoKIyMjIEZ1bmN0aW9ucyBJbmZvCgpgYGB7cn0KU2V1cmF0Ojo6RG9IZWF0bWFwCmBgYAoKYGBge3J9Cm1vbm9jbGU6OjpwbG90X3BzZXVkb3RpbWVfaGVhdG1hcApgYGAKCmBgYHtyfQpnZXRBbnl3aGVyZShhZ2dyZWdhdGVfZ2VuZV9leHByZXNzaW9uKQpgYGAKCnNvIGVzc2VudGlhbGx5IGl0IGZpcnN0IHRha2VzIHRoZSBjb3VudHMgbWF0cml4IGFuZCBzdWJzZXRzIGl0IGJ5IHlvdXIgZ2VuZSBncm91cHMsIHRoZW4gaXQgc3VtcyB0aGUgdmFsdWVzIC0gaWYgeW91IHNwZWNpZnkgc2NhbGUgdGhlbiBpdCB3aWxsIGNhbGN1YWx0ZSB0aGUgeiBzY29yZSBvZiB0aGUgdHJhbnNmb3JtZWQgZGF0YWZyYW1lIAoKCgoKCgoKIyMgQS4gRGlmZnVzaW9uIE1hcAoKY29uc3RydWN0IG1hcApgYGB7cn0KIyMgY29uc3RydWN0IGRpZmZ1c2lvbiBtYXAKIyMgaHR0cDovL3d3dy5iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL2RldmVsL2Jpb2MvdmlnbmV0dGVzL3NsaW5nc2hvdC9pbnN0L2RvYy92aWduZXR0ZS5odG1sCiMjIGlucHV0IGlzIGEgdHJhbnNmb3JtZWQgZXhwcmVzc2lvbiBtYXRyaXggKGdlbmVzIGFzIGNvbHMgYW5kIGNlbGxzIGFzIHJvd3MpCmRtIDwtIERpZmZ1c2lvbk1hcCh0KGFzLmRhdGEuZnJhbWUodGVueC5tdXRhbnQuaW50ZWdyYXRlZC5zZXhAYXNzYXlzJGludGVncmF0ZWRAZGF0YSkpKQoKIyMgZXh0cmFjdCBtZXRhIGRhdGEgZm9yIHBsb3R0aW5nCmRmX21ldGFfZGF0YSA8LSAoYXMuZGF0YS5mcmFtZSh0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEpKQoKIyMgbWFrZSBjb21iaW5lZCBkYXRhZnJhbWUKcmQyIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoREMxID0gZG0kREMxLCBEQzIgPSBkbSREQzIsIGlkZW50aXR5ID0gYXMuZmFjdG9yKGFzLmNoYXJhY3Rlcih0ZW54Lm11dGFudC5pbnRlZ3JhdGVkLnNleEBtZXRhLmRhdGEkcG9zdF9pbnRlZ3JhdGlvbl9jbHVzdGVycykpKSkKCiMjIHBsb3QKZ2dwbG90KHJkMiwgYWVzKHggPSBEQzEsIHkgPSBEQzIsIGNvbG91ciA9IGFzLmNoYXJhY3RlcihpZGVudGl0eSkpKSArIGdlb21fcG9pbnQoc2l6ZSA9IDEpICsgCiAgdGhlbWUoYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKSArIAogIHRoZW1lX2NsYXNzaWMoKQpgYGAK